Merge branch 'dev' of https://github.com/prusa3d/PrusaSlicer into et_reload_from_disk

This commit is contained in:
Enrico Turri 2019-09-06 12:22:45 +02:00
commit d6c3c766aa
63 changed files with 1111 additions and 1487 deletions

View File

@ -247,7 +247,7 @@ extern void its_transform(indexed_triangle_set &its, T *trafo3x4)
template<typename T>
inline void its_transform(indexed_triangle_set &its, const Eigen::Transform<T, 3, Eigen::Affine, Eigen::DontAlign>& t)
{
const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> r = t.matrix().template block<3, 3>(0, 0);
//const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> r = t.matrix().template block<3, 3>(0, 0);
for (stl_vertex &v : its.vertices)
v = (t * v.template cast<T>()).template cast<float>().eval();
}

View File

@ -13,103 +13,200 @@
namespace Slic3r {
struct SurfaceGroupAttrib
struct SurfaceFillParams
{
SurfaceGroupAttrib() : is_solid(false), flow_width(0.f), pattern(-1) {}
bool operator==(const SurfaceGroupAttrib &other) const
{ return is_solid == other.is_solid && flow_width == other.flow_width && pattern == other.pattern; }
bool is_solid;
float flow_width;
// pattern is of type InfillPattern, -1 for an unset pattern.
int pattern;
SurfaceFillParams() : flow(0.f, 0.f, 0.f, false) { memset(this, 0, sizeof(*this)); }
// Zero based extruder ID.
unsigned int extruder;
// Infill pattern, adjusted for the density etc.
InfillPattern pattern;
// FillBase
// in unscaled coordinates
coordf_t spacing;
// infill / perimeter overlap, in unscaled coordinates
coordf_t overlap;
// Angle as provided by the region config, in radians.
float angle;
// Non-negative for a bridge.
float bridge_angle;
// FillParams
float density;
// Don't connect the fill lines around the inner perimeter.
bool dont_connect;
// Don't adjust spacing to fill the space evenly.
bool dont_adjust;
// width, height of extrusion, nozzle diameter, is bridge
// For the output, for fill generator.
Flow flow;
// For the output
ExtrusionRole extrusion_role;
// Various print settings?
// Index of this entry in a linear vector.
size_t idx;
bool operator<(const SurfaceFillParams &rhs) const {
#define RETURN_COMPARE_NON_EQUAL(KEY) if (this->KEY < rhs.KEY) return true; if (this->KEY > rhs.KEY) return false;
#define RETURN_COMPARE_NON_EQUAL_TYPED(TYPE, KEY) if (TYPE(this->KEY) < TYPE(rhs.KEY)) return true; if (TYPE(this->KEY) > TYPE(rhs.KEY)) return false;
// Sort first by decreasing bridging angle, so that the bridges are processed with priority when trimming one layer by the other.
if (this->bridge_angle > rhs.bridge_angle) return true;
if (this->bridge_angle < rhs.bridge_angle) return false;
RETURN_COMPARE_NON_EQUAL(extruder);
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, pattern);
RETURN_COMPARE_NON_EQUAL(spacing);
RETURN_COMPARE_NON_EQUAL(overlap);
RETURN_COMPARE_NON_EQUAL(angle);
RETURN_COMPARE_NON_EQUAL(density);
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_connect);
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_adjust);
RETURN_COMPARE_NON_EQUAL(flow.width);
RETURN_COMPARE_NON_EQUAL(flow.height);
RETURN_COMPARE_NON_EQUAL(flow.nozzle_diameter);
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, flow.bridge);
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, extrusion_role);
return false;
}
bool operator==(const SurfaceFillParams &rhs) const {
return this->extruder == rhs.extruder &&
this->pattern == rhs.pattern &&
this->pattern == rhs.pattern &&
this->spacing == rhs.spacing &&
this->overlap == rhs.overlap &&
this->angle == rhs.angle &&
this->density == rhs.density &&
this->dont_connect == rhs.dont_connect &&
this->dont_adjust == rhs.dont_adjust &&
this->flow == rhs.flow &&
this->extrusion_role == rhs.extrusion_role;
}
};
// Generate infills for Slic3r::Layer::Region.
// The Slic3r::Layer::Region at this point of time may contain
// surfaces of various types (internal/bridge/top/bottom/solid).
// The infills are generated on the groups of surfaces with a compatible type.
// Returns an array of Slic3r::ExtrusionPath::Collection objects containing the infills generaed now
// and the thin fills generated by generate_perimeters().
void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
{
// Slic3r::debugf "Filling layer %d:\n", $layerm->layer->id;
double fill_density = layerm.region()->config().fill_density;
Flow infill_flow = layerm.flow(frInfill);
Flow solid_infill_flow = layerm.flow(frSolidInfill);
Flow top_solid_infill_flow = layerm.flow(frTopSolidInfill);
struct SurfaceFill {
SurfaceFill(const SurfaceFillParams& params) : region_id(size_t(-1)), surface(stCount, ExPolygon()), params(params) {}
Surfaces surfaces;
// merge adjacent surfaces
// in case of bridge surfaces, the ones with defined angle will be attached to the ones
// without any angle (shouldn't this logic be moved to process_external_surfaces()?)
{
Polygons polygons_bridged;
polygons_bridged.reserve(layerm.fill_surfaces.surfaces.size());
for (Surfaces::iterator it = layerm.fill_surfaces.surfaces.begin(); it != layerm.fill_surfaces.surfaces.end(); ++ it)
if (it->bridge_angle >= 0)
polygons_append(polygons_bridged, *it);
// group surfaces by distinct properties (equal surface_type, thickness, thickness_layers, bridge_angle)
// group is of type Slic3r::SurfaceCollection
//FIXME: Use some smart heuristics to merge similar surfaces to eliminate tiny regions.
std::vector<SurfacesPtr> groups;
layerm.fill_surfaces.group(&groups);
// merge compatible groups (we can generate continuous infill for them)
{
// cache flow widths and patterns used for all solid groups
// (we'll use them for comparing compatible groups)
std::vector<SurfaceGroupAttrib> group_attrib(groups.size());
for (size_t i = 0; i < groups.size(); ++ i) {
// we can only merge solid non-bridge surfaces, so discard
// non-solid surfaces
const Surface &surface = *groups[i].front();
if (surface.is_solid() && (!surface.is_bridge() || layerm.layer()->id() == 0)) {
group_attrib[i].is_solid = true;
group_attrib[i].flow_width = (surface.surface_type == stTop) ? top_solid_infill_flow.width : solid_infill_flow.width;
group_attrib[i].pattern = surface.is_external() ?
size_t region_id;
Surface surface;
ExPolygons expolygons;
SurfaceFillParams params;
};
std::vector<SurfaceFill> group_fills(const Layer &layer)
{
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;
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);
for (const Surface &surface : layerm.fill_surfaces.surfaces)
if (surface.surface_type == stInternalVoid)
has_internal_voids = true;
else {
FlowRole extrusion_role = (surface.surface_type == stTop) ? frTopSolidInfill : (surface.is_solid() ? frSolidInfill : frInfill);
bool is_bridge = layerm.layer()->id() > 0 && surface.is_bridge();
params.extruder = layerm.region()->extruder(extrusion_role);
params.pattern = layerm.region()->config().fill_pattern.value;
params.density = float(layerm.region()->config().fill_density);
if (surface.is_solid()) {
params.density = 100.f;
params.pattern = (surface.is_external() && ! is_bridge) ?
(surface.is_top() ? layerm.region()->config().top_fill_pattern.value : layerm.region()->config().bottom_fill_pattern.value) :
ipRectilinear;
}
}
// Loop through solid groups, find compatible groups and append them to this one.
for (size_t i = 0; i < groups.size(); ++ i) {
if (! group_attrib[i].is_solid)
continue;
for (size_t j = i + 1; j < groups.size();) {
if (group_attrib[i] == group_attrib[j]) {
// groups are compatible, merge them
groups[i].insert(groups[i].end(), groups[j].begin(), groups[j].end());
groups.erase(groups.begin() + j);
group_attrib.erase(group_attrib.begin() + j);
} else
++ j;
}
}
}
// Give priority to bridges. Process the bridges in the first round, the rest of the surfaces in the 2nd round.
for (size_t round = 0; round < 2; ++ round) {
for (std::vector<SurfacesPtr>::iterator it_group = groups.begin(); it_group != groups.end(); ++ it_group) {
const SurfacesPtr &group = *it_group;
bool is_bridge = group.front()->bridge_angle >= 0;
if (is_bridge != (round == 0))
continue;
// Make a union of polygons defining the infiill regions of a group, use a safety offset.
Polygons union_p = union_(to_polygons(*it_group), true);
// Subtract surfaces having a defined bridge_angle from any other, use a safety offset.
if (! polygons_bridged.empty() && ! is_bridge)
union_p = diff(union_p, polygons_bridged, true);
// subtract any other surface already processed
//FIXME Vojtech: Because the bridge surfaces came first, they are subtracted twice!
// Using group.front() as a template.
surfaces_append(surfaces, diff_ex(union_p, to_polygons(surfaces), true), *group.front());
}
}
}
ipRectilinear;
} else if (params.density <= 0)
continue;
params.extrusion_role =
is_bridge ?
erBridgeInfill :
(surface.is_solid() ?
((surface.surface_type == stTop) ? erTopSolidInfill : erSolidInfill) :
erInternalInfill);
params.bridge_angle = float(surface.bridge_angle);
params.angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value));
// calculate the actual flow we'll be using for this infill
params.flow = layerm.region()->flow(
extrusion_role,
(surface.thickness == -1) ? layerm.layer()->height : surface.thickness, // extrusion height
is_bridge || Fill::use_bridge_flow(params.pattern), // bridge flow?
layerm.layer()->id() == 0, // first layer?
-1, // auto width
*layerm.layer()->object()
);
// Calculate flow spacing for infill pattern generation.
if (! surface.is_solid() && ! is_bridge) {
// it's internal infill, so we can calculate a generic flow spacing
// for all layers, for avoiding the ugly effect of
// misaligned infill on first layer because of different extrusion width and
// layer height
params.spacing = layerm.region()->flow(
frInfill,
layerm.layer()->object()->config().layer_height.value, // TODO: handle infill_every_layers?
false, // no bridge
false, // no first layer
-1, // auto width
*layer.object()
).spacing();
} else
params.spacing = params.flow.spacing();
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);
}
}
surface_fills.reserve(set_surface_params.size());
for (const SurfaceFillParams &params : set_surface_params) {
const_cast<SurfaceFillParams&>(params).idx = surface_fills.size();
surface_fills.emplace_back(params);
}
for (size_t region_id = 0; region_id < layer.regions().size(); ++ region_id) {
const LayerRegion &layerm = *layer.regions()[region_id];
for (const Surface &surface : layerm.fill_surfaces.surfaces)
if (surface.surface_type != stInternalVoid) {
const SurfaceFillParams *params = region_to_surface_params[region_id][&surface - &layerm.fill_surfaces.surfaces.front()];
if (params != nullptr) {
SurfaceFill &fill = surface_fills[params->idx];
if (fill.region_id == size_t(-1)) {
fill.region_id = region_id;
fill.surface = surface;
fill.expolygons.emplace_back(std::move(fill.surface.expolygon));
} else
fill.expolygons.emplace_back(surface.expolygon);
}
}
}
{
Polygons all_polygons;
for (SurfaceFill &fill : surface_fills)
if (! fill.expolygons.empty() && (fill.expolygons.size() > 1 || ! all_polygons.empty())) {
Polygons polys = to_polygons(std::move(fill.expolygons));
// Make a union of polygons, use a safety offset, subtract the preceding polygons.
// Bridges are processed first (see SurfaceFill::operator<())
fill.expolygons = all_polygons.empty() ? union_ex(polys, true) : diff_ex(polys, all_polygons, true);
append(all_polygons, std::move(polys));
}
}
// we need to detect any narrow surfaces that might collapse
// when adding spacing below
// such narrow surfaces are often generated in sloping walls
@ -119,155 +216,170 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
// we are going to grow such regions by overlapping them with the void (if any)
// TODO: detect and investigate whether there could be narrow regions without
// any void neighbors
{
coord_t distance_between_surfaces = std::max(
std::max(infill_flow.scaled_spacing(), solid_infill_flow.scaled_spacing()),
top_solid_infill_flow.scaled_spacing());
Polygons surfaces_polygons = to_polygons(surfaces);
Polygons collapsed = diff(
surfaces_polygons,
offset2(surfaces_polygons, (float)-distance_between_surfaces/2, (float)+distance_between_surfaces/2),
true);
Polygons to_subtract;
to_subtract.reserve(collapsed.size() + number_polygons(surfaces));
for (Surfaces::const_iterator it_surface = surfaces.begin(); it_surface != surfaces.end(); ++ it_surface)
if (it_surface->surface_type == stInternalVoid)
polygons_append(to_subtract, *it_surface);
polygons_append(to_subtract, collapsed);
surfaces_append(
surfaces,
intersection_ex(
offset(collapsed, (float)distance_between_surfaces),
to_subtract,
true),
stInternalSolid);
if (has_internal_voids) {
// Internal voids are generated only if "infill_only_where_needed" or "infill_every_layers" are active.
coord_t distance_between_surfaces = 0;
Polygons surfaces_polygons;
Polygons voids;
int region_internal_infill = -1;
int region_solid_infill = -1;
int region_some_infill = -1;
for (SurfaceFill &surface_fill : surface_fills)
if (! surface_fill.expolygons.empty()) {
distance_between_surfaces = std::max(distance_between_surfaces, surface_fill.params.flow.scaled_spacing());
append((surface_fill.surface.surface_type == stInternalVoid) ? voids : surfaces_polygons, to_polygons(surface_fill.expolygons));
if (surface_fill.surface.surface_type == stInternalSolid)
region_internal_infill = (int)surface_fill.region_id;
if (surface_fill.surface.is_solid())
region_solid_infill = (int)surface_fill.region_id;
if (surface_fill.surface.surface_type != stInternalVoid)
region_some_infill = (int)surface_fill.region_id;
}
if (! voids.empty() && ! surfaces_polygons.empty()) {
// First clip voids by the printing polygons, as the voids were ignored by the loop above during mutual clipping.
voids = diff(voids, surfaces_polygons);
// Corners of infill regions, which would not be filled with an extrusion path with a radius of distance_between_surfaces/2
Polygons collapsed = diff(
surfaces_polygons,
offset2(surfaces_polygons, (float)-distance_between_surfaces/2, (float)+distance_between_surfaces/2),
true);
//FIXME why the voids are added to collapsed here? First it is expensive, second the result may lead to some unwanted regions being
// added if two offsetted void regions merge.
// polygons_append(voids, collapsed);
ExPolygons extensions = intersection_ex(offset(collapsed, (float)distance_between_surfaces), voids, true);
// Now find an internal infill SurfaceFill to add these extrusions to.
SurfaceFill *internal_solid_fill = nullptr;
unsigned int region_id = 0;
if (region_internal_infill != -1)
region_id = region_internal_infill;
else if (region_solid_infill != -1)
region_id = region_solid_infill;
else if (region_some_infill != -1)
region_id = region_some_infill;
const LayerRegion& layerm = *layer.regions()[region_id];
for (SurfaceFill &surface_fill : surface_fills)
if (surface_fill.surface.surface_type == stInternalSolid && std::abs(layerm.layer()->height - surface_fill.params.flow.height) < EPSILON) {
internal_solid_fill = &surface_fill;
break;
}
if (internal_solid_fill == nullptr) {
// Produce another solid fill.
params.extruder = layerm.region()->extruder(frSolidInfill);
params.pattern = ipRectilinear;
params.density = 100.f;
params.extrusion_role = erInternalInfill;
params.angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value));
// calculate the actual flow we'll be using for this infill
params.flow = layerm.region()->flow(
frSolidInfill,
layerm.layer()->height, // extrusion height
false, // bridge flow?
layerm.layer()->id() == 0, // first layer?
-1, // auto width
*layer.object()
);
params.spacing = params.flow.spacing();
surface_fills.emplace_back(params);
surface_fills.back().surface.surface_type = stInternalSolid;
surface_fills.back().surface.thickness = layer.height;
surface_fills.back().expolygons = std::move(extensions);
} else {
append(extensions, std::move(internal_solid_fill->expolygons));
internal_solid_fill->expolygons = union_ex(extensions);
}
}
}
if (0) {
// require "Slic3r/SVG.pm";
// Slic3r::SVG::output("fill_" . $layerm->print_z . ".svg",
// expolygons => [ map $_->expolygon, grep !$_->is_solid, @surfaces ],
// red_expolygons => [ map $_->expolygon, grep $_->is_solid, @surfaces ],
// );
}
return surface_fills;
}
// friend to Layer
void Layer::make_fills()
{
for (LayerRegion *layerm : m_regions)
layerm->fills.clear();
std::vector<SurfaceFill> surface_fills = group_fills(*this);
const Slic3r::BoundingBox bbox = this->object()->bounding_box();
for (SurfaceFill &surface_fill : surface_fills) {
// Create the filler object.
std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(surface_fill.params.pattern));
f->set_bounding_box(bbox);
f->layer_id = this->id();
f->z = this->print_z;
f->angle = surface_fill.params.angle;
f->spacing = surface_fill.params.spacing;
for (const Surface &surface : surfaces) {
if (surface.surface_type == stInternalVoid)
continue;
InfillPattern fill_pattern = layerm.region()->config().fill_pattern.value;
double density = fill_density;
FlowRole role = (surface.surface_type == stTop) ? frTopSolidInfill :
(surface.is_solid() ? frSolidInfill : frInfill);
bool is_bridge = layerm.layer()->id() > 0 && surface.is_bridge();
if (surface.is_solid()) {
density = 100.;
fill_pattern = (surface.is_external() && ! is_bridge) ?
(surface.is_top() ? layerm.region()->config().top_fill_pattern.value : layerm.region()->config().bottom_fill_pattern.value) :
ipRectilinear;
} else if (density <= 0)
continue;
// get filler object
std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(fill_pattern));
f->set_bounding_box(layerm.layer()->object()->bounding_box());
// calculate the actual flow we'll be using for this infill
coordf_t h = (surface.thickness == -1) ? layerm.layer()->height : surface.thickness;
Flow flow = layerm.region()->flow(
role,
h,
is_bridge || f->use_bridge_flow(), // bridge flow?
layerm.layer()->id() == 0, // first layer?
-1, // auto width
*layerm.layer()->object()
);
// calculate flow spacing for infill pattern generation
bool using_internal_flow = false;
if (! surface.is_solid() && ! is_bridge) {
// it's internal infill, so we can calculate a generic flow spacing
// for all layers, for avoiding the ugly effect of
// misaligned infill on first layer because of different extrusion width and
// layer height
Flow internal_flow = layerm.region()->flow(
frInfill,
layerm.layer()->object()->config().layer_height.value, // TODO: handle infill_every_layers?
false, // no bridge
false, // no first layer
-1, // auto width
*layerm.layer()->object()
);
f->spacing = internal_flow.spacing();
using_internal_flow = true;
} else {
f->spacing = flow.spacing();
}
bool using_internal_flow = ! surface_fill.surface.is_solid() && ! surface_fill.params.flow.bridge;
double link_max_length = 0.;
if (! is_bridge) {
if (! surface_fill.params.flow.bridge) {
#if 0
link_max_length = layerm.region()->config().get_abs_value(surface.is_external() ? "external_fill_link_max_length" : "fill_link_max_length", flow.spacing());
// printf("flow spacing: %f, is_external: %d, link_max_length: %lf\n", flow.spacing(), int(surface.is_external()), link_max_length);
#else
if (density > 80.) // 80%
if (surface_fill.params.density > 80.) // 80%
link_max_length = 3. * f->spacing;
#endif
}
f->layer_id = layerm.layer()->id();
f->z = layerm.layer()->print_z;
f->angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value));
// Maximum length of the perimeter segment linking two infill lines.
f->link_max_length = (coord_t)scale_(link_max_length);
// Used by the concentric infill pattern to clip the loops to create extrusion paths.
f->loop_clipping = coord_t(scale_(flow.nozzle_diameter) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER);
// f->layer_height = h;
f->loop_clipping = coord_t(scale_(surface_fill.params.flow.nozzle_diameter) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER);
// apply half spacing using this flow's own spacing and generate infill
FillParams params;
params.density = float(0.01 * density);
// params.dont_adjust = true;
params.dont_adjust = false;
Polylines polylines = f->fill_surface(&surface, params);
if (polylines.empty())
continue;
params.density = float(0.01 * surface_fill.params.density);
params.dont_adjust = surface_fill.params.dont_adjust; // false
// calculate actual flow from spacing (which might have been adjusted by the infill
// pattern generator)
if (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->flow_spacing
} else {
flow = Flow::new_from_spacing(f->spacing, flow.nozzle_diameter, (float)h, is_bridge || f->use_bridge_flow());
}
// Save into layer.
auto *eec = new ExtrusionEntityCollection();
out.entities.push_back(eec);
// Only concentric fills are not sorted.
eec->no_sort = f->no_sort();
extrusion_entities_append_paths(
eec->entities, std::move(polylines),
is_bridge ?
erBridgeInfill :
(surface.is_solid() ?
((surface.surface_type == stTop) ? erTopSolidInfill : erSolidInfill) :
erInternalInfill),
flow.mm3_per_mm(), flow.width, flow.height);
for (ExPolygon &expoly : surface_fill.expolygons) {
surface_fill.surface.expolygon = std::move(expoly);
Polylines polylines = f->fill_surface(&surface_fill.surface, params);
if (! polylines.empty()) {
// calculate actual flow from spacing (which might have been adjusted by the infill
// pattern generator)
double flow_mm3_per_mm = surface_fill.params.flow.mm3_per_mm();
double flow_width = surface_fill.params.flow.width;
if (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 = Flow::new_from_spacing(float(f->spacing), surface_fill.params.flow.nozzle_diameter, surface_fill.params.flow.height, surface_fill.params.flow.bridge);
flow_mm3_per_mm = new_flow.mm3_per_mm();
flow_width = new_flow.width;
}
// Save into layer.
auto *eec = new ExtrusionEntityCollection();
m_regions[surface_fill.region_id]->fills.entities.push_back(eec);
// Only concentric fills are not sorted.
eec->no_sort = f->no_sort();
extrusion_entities_append_paths(
eec->entities, std::move(polylines),
surface_fill.params.extrusion_role,
flow_mm3_per_mm, float(flow_width), surface_fill.params.flow.height);
}
}
}
// add thin fill regions
// thin_fills are of C++ Slic3r::ExtrusionEntityCollection, perl type Slic3r::ExtrusionPath::Collection
// Unpacks the collection, creates multiple collections per path.
// The path type could be ExtrusionPath, ExtrusionLoop or ExtrusionEntityCollection.
// Why the paths are unpacked?
for (const ExtrusionEntity *thin_fill : layerm.thin_fills.entities) {
ExtrusionEntityCollection &collection = *(new ExtrusionEntityCollection());
out.entities.push_back(&collection);
collection.entities.push_back(thin_fill->clone());
}
for (LayerRegion *layerm : m_regions)
for (const ExtrusionEntity *thin_fill : layerm->thin_fills.entities) {
ExtrusionEntityCollection &collection = *(new ExtrusionEntityCollection());
layerm->fills.entities.push_back(&collection);
collection.entities.push_back(thin_fill->clone());
}
#ifndef NDEBUG
for (LayerRegion *layerm : m_regions)
for (size_t i = 0; i < layerm->fills.entities.size(); ++ i)
assert(dynamic_cast<ExtrusionEntityCollection*>(layerm->fills.entities[i]) != nullptr);
#endif
}
} // namespace Slic3r

View File

@ -34,7 +34,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
case ipArchimedeanChords: return new FillArchimedeanChords();
case ipHilbertCurve: return new FillHilbertCurve();
case ipOctagramSpiral: return new FillOctagramSpiral();
default: throw std::invalid_argument("unknown type");;
default: throw std::invalid_argument("unknown type");
}
}
@ -45,6 +45,24 @@ Fill* Fill::new_from_type(const std::string &type)
return (it == enum_keys_map.end()) ? nullptr : new_from_type(InfillPattern(it->second));
}
// Force initialization of the Fill::use_bridge_flow() internal static map in a thread safe fashion even on compilers
// not supporting thread safe non-static data member initializers.
static bool use_bridge_flow_initializer = Fill::use_bridge_flow(ipGrid);
bool Fill::use_bridge_flow(const InfillPattern type)
{
static std::vector<unsigned char> cached;
if (cached.empty()) {
cached.assign(size_t(ipCount), 0);
for (size_t i = 0; i < cached.size(); ++ i) {
auto *fill = Fill::new_from_type((InfillPattern)i);
cached[i] = fill->use_bridge_flow();
delete fill;
}
}
return cached[type] != 0;
}
Polylines Fill::fill_surface(const Surface *surface, const FillParams &params)
{
// Perform offset.

View File

@ -70,6 +70,7 @@ public:
static Fill* new_from_type(const InfillPattern type);
static Fill* new_from_type(const std::string &type);
static bool use_bridge_flow(const InfillPattern type);
void set_bounding_box(const Slic3r::BoundingBox &bbox) { bounding_box = bbox; }

View File

@ -56,6 +56,8 @@ public:
// Enable some perimeter squish (see INSET_OVERLAP_TOLERANCE).
// Here an overlap of 0.2x external perimeter spacing is allowed for by the elephant foot compensation.
coord_t scaled_elephant_foot_spacing() const { return coord_t(0.5f * float(this->scaled_width() + 0.6f * this->scaled_spacing())); }
bool operator==(const Flow &rhs) const { return this->width == rhs.width && this->height == rhs.height && this->nozzle_diameter == rhs.nozzle_diameter && this->bridge == rhs.bridge; }
static Flow new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height, float bridge_flow_ratio);
// Create a flow from the spacing of extrusion lines.

View File

@ -662,15 +662,19 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
throw std::runtime_error(msg);
}
if (print->config().remaining_times.value) {
BOOST_LOG_TRIVIAL(debug) << "Processing remaining times for normal mode" << log_memory_info();
m_normal_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
GCodeTimeEstimator::PostProcessData normal_data = m_normal_time_estimator.get_post_process_data();
GCodeTimeEstimator::PostProcessData silent_data = m_silent_time_estimator.get_post_process_data();
bool remaining_times_enabled = print->config().remaining_times.value;
BOOST_LOG_TRIVIAL(debug) << "Time estimator post processing" << log_memory_info();
GCodeTimeEstimator::post_process(path_tmp, 60.0f, remaining_times_enabled ? &normal_data : nullptr, (remaining_times_enabled && m_silent_time_estimator_enabled) ? &silent_data : nullptr);
if (remaining_times_enabled)
{
m_normal_time_estimator.reset();
if (m_silent_time_estimator_enabled) {
BOOST_LOG_TRIVIAL(debug) << "Processing remaining times for silent mode" << log_memory_info();
m_silent_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
if (m_silent_time_estimator_enabled)
m_silent_time_estimator.reset();
}
}
// starts analyzer calculations
@ -1738,13 +1742,9 @@ void GCode::process_layer(
// This extrusion is part of certain Region, which tells us which extruder should be used for it:
int correct_extruder_id = Print::get_extruder(*fill, region);
//FIXME what is this?
entity_type=="infills" ?
std::max<int>(0, (is_solid_infill(fill->entities.front()->role()) ? region.config().solid_infill_extruder : region.config().infill_extruder) - 1) :
std::max<int>(region.config().perimeter_extruder.value - 1, 0);
// Let's recover vector of extruder overrides:
const ExtruderPerCopy* entity_overrides = const_cast<LayerTools&>(layer_tools).wiping_extrusions().get_extruder_overrides(fill, correct_extruder_id, (int)layer_to_print.object()->copies().size());
const ExtruderPerCopy* entity_overrides = const_cast<LayerTools&>(layer_tools).wiping_extrusions().get_extruder_overrides(fill, correct_extruder_id, layer_to_print.object()->copies().size());
// Now we must add this extrusion into the by_extruder map, once for each extruder that will print it:
for (unsigned int extruder : layer_tools.extruders)
@ -3027,7 +3027,7 @@ const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtru
// This function takes the eec and appends its entities to either perimeters or infills of this Region (depending on the first parameter)
// It also saves pointer to ExtruderPerCopy struct (for each entity), that holds information about which extruders should be used for which copy.
void GCode::ObjectByExtruder::Island::Region::append(const std::string& type, const ExtrusionEntityCollection* eec, const ExtruderPerCopy* copies_extruder, unsigned int object_copies_num)
void GCode::ObjectByExtruder::Island::Region::append(const std::string& type, const ExtrusionEntityCollection* eec, const ExtruderPerCopy* copies_extruder, size_t object_copies_num)
{
// We are going to manipulate either perimeters or infills, exactly in the same way. Let's create pointers to the proper structure to not repeat ourselves:
ExtrusionEntityCollection* perimeters_or_infills = &infills;

View File

@ -246,7 +246,7 @@ protected:
std::vector<const ExtruderPerCopy*> perimeters_overrides;
// Appends perimeter/infill entities and writes don't indices of those that are not to be extruder as part of perimeter/infill wiping
void append(const std::string& type, const ExtrusionEntityCollection* eec, const ExtruderPerCopy* copy_extruders, unsigned int object_copies_num);
void append(const std::string& type, const ExtrusionEntityCollection* eec, const ExtruderPerCopy* copy_extruders, size_t object_copies_num);
};
std::vector<Region> by_region; // all extrusions for this island, grouped by regions

View File

@ -458,14 +458,14 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
continue;
}
const auto& object = object_list[i];
const PrintObject* object = object_list[i];
// Finds this layer:
auto this_layer_it = std::find_if(object->layers().begin(), object->layers().end(), [&lt](const Layer* lay) { return std::abs(lt.print_z - lay->print_z)<EPSILON; });
if (this_layer_it == object->layers().end())
continue;
const Layer* this_layer = *this_layer_it;
unsigned int num_of_copies = object->copies().size();
size_t num_of_copies = object->copies().size();
for (unsigned int copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves
@ -494,7 +494,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
if ((!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) { // this infill will be used to wipe this extruder
set_extruder_override(fill, copy, new_extruder, num_of_copies);
volume_to_wipe -= fill->total_volume();
volume_to_wipe -= float(fill->total_volume());
}
}
}
@ -512,7 +512,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
if ((!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) {
set_extruder_override(fill, copy, new_extruder, num_of_copies);
volume_to_wipe -= fill->total_volume();
volume_to_wipe -= float(fill->total_volume());
}
}
}
@ -540,9 +540,9 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print)
if (this_layer_it == object->layers().end())
continue;
const Layer* this_layer = *this_layer_it;
unsigned int num_of_copies = object->copies().size();
size_t num_of_copies = object->copies().size();
for (unsigned int copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves
for (size_t copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves
for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) {
const auto& region = *object->print()->regions()[region_id];
@ -598,7 +598,7 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print)
// so -1 was used as "print as usual".
// The resulting vector has to keep track of which extrusions are the ones that were overridden and which were not. In the extruder is used as overridden,
// its number is saved as it is (zero-based index). Usual extrusions are saved as -number-1 (unfortunately there is no negative zero).
const std::vector<int>* WipingExtrusions::get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, int num_of_copies)
const std::vector<int>* WipingExtrusions::get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, size_t num_of_copies)
{
auto entity_map_it = entity_map.find(entity);
if (entity_map_it == entity_map.end())

View File

@ -24,7 +24,7 @@ public:
}
// This is called from GCode::process_layer - see implementation for further comments:
const std::vector<int>* get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, int num_of_copies);
const std::vector<int>* get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, size_t num_of_copies);
// This function goes through all infill entities, decides which ones will be used for wiping and
// marks them by the extruder id. Returns volume that remains to be wiped on the wipe tower:
@ -44,7 +44,7 @@ private:
void set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies);
// Returns true in case that entity is not printed with its usual extruder for a given copy:
bool is_entity_overridden(const ExtrusionEntity* entity, int copy_id) const {
bool is_entity_overridden(const ExtrusionEntity* entity, size_t copy_id) const {
return (entity_map.find(entity) == entity_map.end() ? false : entity_map.at(entity).at(copy_id) != -1);
}

View File

@ -151,7 +151,7 @@ public:
float dx = x - m_current_pos.x();
float dy = y - m_current_pos.y();
double len = sqrt(dx*dx+dy*dy);
float len = std::sqrt(dx*dx+dy*dy);
if (record_length)
m_used_filament_length += e;
@ -159,11 +159,11 @@ public:
Vec2f rotated_current_pos(rotate(m_current_pos + Vec2f(0.f,m_y_shift), m_wipe_tower_width, m_wipe_tower_depth, m_internal_angle)); // this is where we are
Vec2f rot(rotate(Vec2f(x,y+m_y_shift), m_wipe_tower_width, m_wipe_tower_depth, m_internal_angle)); // this is where we want to go
if (! m_preview_suppressed && e > 0.f && len > 0.) {
if (! m_preview_suppressed && e > 0.f && len > 0.f) {
change_analyzer_mm3_per_mm(len, e);
// Width of a squished extrusion, corrected for the roundings of the squished extrusions.
// This is left zero if it is a travel move.
float width = float(double(e) * m_filpar[0].filament_area / (len * m_layer_height));
float width = e * m_filpar[0].filament_area / (len * m_layer_height);
// Correct for the roundings of a squished extrusion.
width += m_layer_height * float(1. - M_PI / 4.);
if (m_extrusions.empty() || m_extrusions.back().pos != rotated_current_pos)
@ -172,10 +172,10 @@ public:
}
m_gcode += "G1";
if (std::abs(rot.x() - rotated_current_pos.x()) > EPSILON)
if (std::abs(rot.x() - rotated_current_pos.x()) > (float)EPSILON)
m_gcode += set_format_X(rot.x());
if (std::abs(rot.y() - rotated_current_pos.y()) > EPSILON)
if (std::abs(rot.y() - rotated_current_pos.y()) > (float)EPSILON)
m_gcode += set_format_Y(rot.y());
@ -184,7 +184,7 @@ public:
if (f != 0.f && f != m_current_feedrate) {
if (limit_volumetric_flow) {
float e_speed = e / (((len == 0) ? std::abs(e) : len) / f * 60.f);
float e_speed = e / (((len == 0.f) ? std::abs(e) : len) / f * 60.f);
f /= std::max(1.f, e_speed / m_filpar[m_current_tool].max_e_speed);
}
m_gcode += set_format_F(f);
@ -194,7 +194,7 @@ public:
m_current_pos.y() = y;
// Update the elapsed time with a rough estimate.
m_elapsed_time += ((len == 0) ? std::abs(e) : len) / m_current_feedrate * 60.f;
m_elapsed_time += ((len == 0.f) ? std::abs(e) : len) / m_current_feedrate * 60.f;
m_gcode += "\n";
return *this;
}
@ -214,7 +214,7 @@ public:
{
float dx = x - m_current_pos.x();
float dy = y - m_current_pos.y();
return extrude_explicit(x, y, sqrt(dx*dx+dy*dy) * m_extrusion_flow, f, true);
return extrude_explicit(x, y, std::sqrt(dx*dx+dy*dy) * m_extrusion_flow, f, true);
}
WipeTowerWriter& extrude(const Vec2f &dest, const float f = 0.f)
@ -311,7 +311,7 @@ public:
return *this;
}
WipeTowerWriter& set_tool(int tool)
WipeTowerWriter& set_tool(unsigned tool)
{
m_current_tool = tool;
return *this;
@ -320,57 +320,52 @@ public:
// Set extruder temperature, don't wait by default.
WipeTowerWriter& set_extruder_temp(int temperature, bool wait = false)
{
char buf[128];
sprintf(buf, "M%d S%d\n", wait ? 109 : 104, temperature);
m_gcode += buf;
m_gcode += "M" + std::to_string(wait ? 109 : 104) + " S" + std::to_string(temperature) + "\n";
return *this;
};
}
// Wait for a period of time (seconds).
WipeTowerWriter& wait(float time)
{
if (time==0)
if (time==0.f)
return *this;
char buf[128];
sprintf(buf, "G4 S%.3f\n", time);
m_gcode += buf;
return *this;
};
}
// Set speed factor override percentage.
WipeTowerWriter& speed_override(int speed)
{
char buf[128];
sprintf(buf, "M220 S%d\n", speed);
m_gcode += buf;
m_gcode += "M220 S" + std::to_string(speed) + "\n";
return *this;
};
}
// Let the firmware back up the active speed override value.
WipeTowerWriter& speed_override_backup()
{
m_gcode += "M220 B\n";
return *this;
};
}
// Let the firmware restore the active speed override value.
WipeTowerWriter& speed_override_restore()
{
m_gcode += "M220 R\n";
return *this;
};
}
// Set digital trimpot motor
WipeTowerWriter& set_extruder_trimpot(int current)
{
char buf[128];
if (m_gcode_flavor == gcfRepRap)
sprintf(buf, "M906 E%d\n", current);
m_gcode += "M906 E";
else
sprintf(buf, "M907 E%d\n", current);
m_gcode += buf;
m_gcode += "M907 E";
m_gcode += std::to_string(current) + "\n";
return *this;
};
}
WipeTowerWriter& flush_planner_queue()
{
@ -386,28 +381,20 @@ public:
}
WipeTowerWriter& comment_with_value(const char *comment, int value)
{
char strvalue[64];
sprintf(strvalue, "%d", value);
m_gcode += std::string(";") + comment + strvalue + "\n";
{
m_gcode += std::string(";") + comment + std::to_string(value) + "\n";
return *this;
};
}
WipeTowerWriter& set_fan(unsigned int speed)
WipeTowerWriter& set_fan(unsigned speed)
{
if (speed == m_last_fan_speed)
return *this;
if (speed == 0)
m_gcode += "M107\n";
else
{
m_gcode += "M106 S";
char buf[128];
sprintf(buf,"%u\n",(unsigned int)(255.0 * speed / 100.0));
m_gcode += buf;
}
else
m_gcode += "M106 S" + std::to_string(unsigned(255.0 * speed / 100.0)) + "\n";
m_last_fan_speed = speed;
return *this;
}
@ -430,7 +417,7 @@ private:
float m_y_shift = 0.f;
float m_wipe_tower_width = 0.f;
float m_wipe_tower_depth = 0.f;
float m_last_fan_speed = 0.f;
unsigned m_last_fan_speed = 0.f;
int current_temp = -1;
const float m_default_analyzer_line_width;
float m_used_filament_length = 0.f;
@ -479,12 +466,12 @@ private:
WipeTower::WipeTower(const PrintConfig& config, const std::vector<std::vector<float>>& wiping_matrix, size_t initial_tool) :
m_semm(config.single_extruder_multi_material.value),
m_wipe_tower_pos(config.wipe_tower_x, config.wipe_tower_y),
m_wipe_tower_width(config.wipe_tower_width),
m_wipe_tower_rotation_angle(config.wipe_tower_rotation_angle),
m_wipe_tower_width(float(config.wipe_tower_width)),
m_wipe_tower_rotation_angle(float(config.wipe_tower_rotation_angle)),
m_y_shift(0.f),
m_z_pos(0.f),
m_is_first_layer(false),
m_bridging(config.wipe_tower_bridging),
m_bridging(float(config.wipe_tower_bridging)),
m_gcode_flavor(config.gcode_flavor),
m_current_tool(initial_tool),
wipe_volumes(wiping_matrix)
@ -492,16 +479,16 @@ WipeTower::WipeTower(const PrintConfig& config, const std::vector<std::vector<fl
// If this is a single extruder MM printer, we will use all the SE-specific config values.
// Otherwise, the defaults will be used to turn off the SE stuff.
if (m_semm) {
m_cooling_tube_retraction = config.cooling_tube_retraction;
m_cooling_tube_length = config.cooling_tube_length;
m_parking_pos_retraction = config.parking_pos_retraction;
m_extra_loading_move = config.extra_loading_move;
m_set_extruder_trimpot = config.high_current_on_filament_swap;
m_cooling_tube_retraction = float(config.cooling_tube_retraction);
m_cooling_tube_length = float(config.cooling_tube_length);
m_parking_pos_retraction = float(config.parking_pos_retraction);
m_extra_loading_move = float(config.extra_loading_move);
m_set_extruder_trimpot = config.high_current_on_filament_swap;
}
// Calculate where the priming lines should be - very naive test not detecting parallelograms or custom shapes
const std::vector<Vec2d>& bed_points = config.bed_shape.values;
m_bed_shape = (bed_points.size() == 4 ? RectangularBed : CircularBed);
m_bed_width = BoundingBoxf(bed_points).size().x();
m_bed_width = float(BoundingBoxf(bed_points).size().x());
}
@ -518,21 +505,21 @@ void WipeTower::set_extruder(size_t idx, const PrintConfig& config)
// If this is a single extruder MM printer, we will use all the SE-specific config values.
// Otherwise, the defaults will be used to turn off the SE stuff.
if (m_semm) {
m_filpar[idx].loading_speed = config.filament_loading_speed.get_at(idx);
m_filpar[idx].loading_speed_start = config.filament_loading_speed_start.get_at(idx);
m_filpar[idx].unloading_speed = config.filament_unloading_speed.get_at(idx);
m_filpar[idx].unloading_speed_start = config.filament_unloading_speed_start.get_at(idx);
m_filpar[idx].delay = config.filament_toolchange_delay.get_at(idx);
m_filpar[idx].loading_speed = float(config.filament_loading_speed.get_at(idx));
m_filpar[idx].loading_speed_start = float(config.filament_loading_speed_start.get_at(idx));
m_filpar[idx].unloading_speed = float(config.filament_unloading_speed.get_at(idx));
m_filpar[idx].unloading_speed_start = float(config.filament_unloading_speed_start.get_at(idx));
m_filpar[idx].delay = float(config.filament_toolchange_delay.get_at(idx));
m_filpar[idx].cooling_moves = config.filament_cooling_moves.get_at(idx);
m_filpar[idx].cooling_initial_speed = config.filament_cooling_initial_speed.get_at(idx);
m_filpar[idx].cooling_final_speed = config.filament_cooling_final_speed.get_at(idx);
m_filpar[idx].cooling_initial_speed = float(config.filament_cooling_initial_speed.get_at(idx));
m_filpar[idx].cooling_final_speed = float(config.filament_cooling_final_speed.get_at(idx));
}
m_filpar[idx].filament_area = float((M_PI/4.f) * pow(config.filament_diameter.get_at(idx), 2)); // all extruders are assumed to have the same filament diameter at this point
float nozzle_diameter = config.nozzle_diameter.get_at(idx);
float nozzle_diameter = float(config.nozzle_diameter.get_at(idx));
m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM
float max_vol_speed = config.filament_max_volumetric_speed.get_at(idx);
float max_vol_speed = float(config.filament_max_volumetric_speed.get_at(idx));
if (max_vol_speed!= 0.f)
m_filpar[idx].max_e_speed = (max_vol_speed / filament_area());
@ -561,7 +548,7 @@ std::vector<WipeTower::ToolChangeResult> WipeTower::prime(
const std::vector<unsigned int> &tools,
// If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower.
// If false, the last priming are will be large enough to wipe the last extruder sufficiently.
bool last_wipe_inside_wipe_tower)
bool /*last_wipe_inside_wipe_tower*/)
{
this->set_layer(first_layer_height, first_layer_height, tools.size(), true, false);
this->m_current_tool = tools.front();
@ -696,7 +683,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(unsigned int tool, bool last_
box_coordinates cleaning_box(
Vec2f(m_perimeter_width / 2.f, m_perimeter_width / 2.f),
m_wipe_tower_width - m_perimeter_width,
(tool != (unsigned int)(-1) ? /*m_layer_info->depth*/wipe_area+m_depth_traversed-0.5*m_perimeter_width
(tool != (unsigned int)(-1) ? /*m_layer_info->depth*/wipe_area+m_depth_traversed-0.5f*m_perimeter_width
: m_wipe_tower_depth-m_perimeter_width));
WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar);
@ -802,7 +789,7 @@ WipeTower::ToolChangeResult WipeTower::toolchange_Brim(bool sideOnly, float y_of
// Extrude 4 rounds of a brim around the future wipe tower.
box_coordinates box(wipeTower_box);
for (size_t i = 0; i < 4; ++ i) {
box.expand(m_perimeter_width - m_layer_height*(1.f-M_PI_4)); // the brim shall have 'normal' spacing with no extra void space
box.expand(m_perimeter_width - m_layer_height*float(1.-M_PI_4)); // the brim shall have 'normal' spacing with no extra void space
writer.travel (box.ld, 7000)
.extrude(box.lu, 2100).extrude(box.ru)
.extrude(box.rd ).extrude(box.ld);
@ -911,8 +898,8 @@ void WipeTower::toolchange_Unload(
const float x = volume_to_length(m_filpar[m_current_tool].ramming_speed[i] * 0.25f, line_width, m_layer_height);
const float e = m_filpar[m_current_tool].ramming_speed[i] * 0.25f / filament_area(); // transform volume per sec to E move;
const float dist = std::min(x - e_done, remaining); // distance to travel for either the next 0.25s, or to the next turnaround
const float actual_time = dist/x * 0.25;
writer.ram(writer.x(), writer.x() + (m_left_to_right ? 1.f : -1.f) * dist, 0, 0, e * (dist / x), dist / (actual_time / 60.));
const float actual_time = dist/x * 0.25f;
writer.ram(writer.x(), writer.x() + (m_left_to_right ? 1.f : -1.f) * dist, 0.f, 0.f, e * (dist / x), dist / (actual_time / 60.f));
remaining -= dist;
if (remaining < WT_EPSILON) { // we reached a turning point
@ -995,8 +982,8 @@ void WipeTower::toolchange_Unload(
// Change the tool, set a speed override for soluble and flex materials.
void WipeTower::toolchange_Change(
WipeTowerWriter &writer,
const unsigned int new_tool,
const std::string& new_material)
const size_t new_tool,
const std::string& new_material)
{
// Ask the writer about how much of the old filament we consumed:
if (m_current_tool < m_used_filament_length.size())
@ -1091,21 +1078,21 @@ void WipeTower::toolchange_Wipe(
float traversed_x = writer.x();
if (m_left_to_right)
writer.extrude(xr - (i % 4 == 0 ? 0 : 1.5*m_perimeter_width), writer.y(), wipe_speed * wipe_coeff);
writer.extrude(xr - (i % 4 == 0 ? 0 : 1.5f*m_perimeter_width), writer.y(), wipe_speed * wipe_coeff);
else
writer.extrude(xl + (i % 4 == 1 ? 0 : 1.5*m_perimeter_width), writer.y(), wipe_speed * wipe_coeff);
writer.extrude(xl + (i % 4 == 1 ? 0 : 1.5f*m_perimeter_width), writer.y(), wipe_speed * wipe_coeff);
if (writer.y()+EPSILON > cleaning_box.lu.y()-0.5f*m_perimeter_width)
if (writer.y()+float(EPSILON) > cleaning_box.lu.y()-0.5f*m_perimeter_width)
break; // in case next line would not fit
traversed_x -= writer.x();
x_to_wipe -= fabs(traversed_x);
x_to_wipe -= std::abs(traversed_x);
if (x_to_wipe < WT_EPSILON) {
writer.travel(m_left_to_right ? xl + 1.5*m_perimeter_width : xr - 1.5*m_perimeter_width, writer.y(), 7200);
writer.travel(m_left_to_right ? xl + 1.5f*m_perimeter_width : xr - 1.5f*m_perimeter_width, writer.y(), 7200);
break;
}
// stepping to the next line:
writer.extrude(writer.x() + (i % 4 == 0 ? -1.f : (i % 4 == 1 ? 1.f : 0.f)) * 1.5*m_perimeter_width, writer.y() + dy);
writer.extrude(writer.x() + (i % 4 == 0 ? -1.f : (i % 4 == 1 ? 1.f : 0.f)) * 1.5f*m_perimeter_width, writer.y() + dy);
m_left_to_right = !m_left_to_right;
}
@ -1188,7 +1175,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer()
writer.travel(fill_box.ld + Vec2f(m_perimeter_width * 2, 0.f))
.extrude(fill_box.lu + Vec2f(m_perimeter_width * 2, 0.f), 2900 * speed_factor);
const int n = 1+(right-left)/(m_bridging);
const int n = 1+int((right-left)/m_bridging);
const float dx = (right-left)/n;
for (int i=1;i<=n;++i) {
float x=left+dx*i;
@ -1267,7 +1254,7 @@ void WipeTower::plan_tower()
for (auto& layer : m_plan)
layer.depth = 0.f;
for (int layer_index = m_plan.size() - 1; layer_index >= 0; --layer_index)
for (int layer_index = int(m_plan.size()) - 1; layer_index >= 0; --layer_index)
{
float this_layer_depth = std::max(m_plan[layer_index].depth, m_plan[layer_index].toolchanges_depth());
m_plan[layer_index].depth = this_layer_depth;

View File

@ -7,21 +7,21 @@
#include <utility>
#include <algorithm>
#include "libslic3r/PrintConfig.hpp"
#include "libslic3r/Point.hpp"
namespace Slic3r
{
class WipeTowerWriter;
class PrintConfig;
enum GCodeFlavor : unsigned char;
class WipeTower
{
public:
struct Extrusion
{
{
Extrusion(const Vec2f &pos, float width, unsigned int tool) : pos(pos), width(width), tool(tool) {}
// End position of this extrusion.
Vec2f pos;
@ -79,7 +79,6 @@ public:
// width -- width of wipe tower in mm ( default 60 mm - leave as it is )
// wipe_area -- space available for one toolchange in mm
WipeTower(const PrintConfig& config, const std::vector<std::vector<float>>& wiping_matrix, size_t initial_tool);
virtual ~WipeTower() {}
// Set the extruder properties.
@ -244,7 +243,7 @@ private:
bool m_print_brim = true;
// A fill-in direction (positive Y, negative Y) alternates with each layer.
wipe_shape m_current_shape = SHAPE_NORMAL;
unsigned int m_current_tool = 0;
size_t m_current_tool = 0;
const std::vector<std::vector<float>> wipe_volumes;
float m_depth_traversed = 0.f; // Current y position at the wipe tower.
@ -309,13 +308,13 @@ private:
// to store information about tool changes for a given layer
struct WipeTowerInfo{
struct ToolChange {
unsigned int old_tool;
unsigned int new_tool;
size_t old_tool;
size_t new_tool;
float required_depth;
float ramming_depth;
float first_wipe_line;
float wipe_volume;
ToolChange(unsigned int old, unsigned int newtool, float depth=0.f, float ramming_depth=0.f, float fwl=0.f, float wv=0.f)
ToolChange(size_t old, size_t newtool, float depth=0.f, float ramming_depth=0.f, float fwl=0.f, float wv=0.f)
: old_tool{old}, new_tool{newtool}, required_depth{depth}, ramming_depth{ramming_depth}, first_wipe_line{fwl}, wipe_volume{wv} {}
};
float z; // z position of the layer
@ -350,7 +349,7 @@ private:
void toolchange_Change(
WipeTowerWriter &writer,
const unsigned int new_tool,
const size_t new_tool,
const std::string& new_material);
void toolchange_Load(

View File

@ -173,9 +173,7 @@ namespace Slic3r {
const std::string GCodeTimeEstimator::Normal_Last_M73_Output_Placeholder_Tag = "; _TE_NORMAL_LAST_M73_OUTPUT_PLACEHOLDER";
const std::string GCodeTimeEstimator::Silent_Last_M73_Output_Placeholder_Tag = "; _TE_SILENT_LAST_M73_OUTPUT_PLACEHOLDER";
// temporary human readable form to use until not removed from gcode by the new post-process method
const std::string GCodeTimeEstimator::Color_Change_Tag = "PRINT_COLOR_CHANGE";
// const std::string GCodeTimeEstimator::Color_Change_Tag = "_TE_COLOR_CHANGE";
GCodeTimeEstimator::GCodeTimeEstimator(EMode mode)
: m_mode(mode)
@ -273,130 +271,138 @@ namespace Slic3r {
#endif // ENABLE_MOVE_STATS
}
bool GCodeTimeEstimator::post_process_remaining_times(const std::string& filename, float interval)
bool GCodeTimeEstimator::post_process(const std::string& filename, float interval_sec, const PostProcessData* const normal_mode, const PostProcessData* const silent_mode)
{
boost::nowide::ifstream in(filename);
if (!in.good())
throw std::runtime_error(std::string("Remaining times export failed.\nCannot open file for reading.\n"));
throw std::runtime_error(std::string("Time estimator post process export failed.\nCannot open file for reading.\n"));
std::string path_tmp = filename + ".times";
std::string path_tmp = filename + ".postprocess";
FILE* out = boost::nowide::fopen(path_tmp.c_str(), "wb");
if (out == nullptr)
throw std::runtime_error(std::string("Remaining times export failed.\nCannot open file for writing.\n"));
throw std::runtime_error(std::string("Time estimator post process export failed.\nCannot open file for writing.\n"));
std::string time_mask;
switch (m_mode)
{
default:
case Normal:
{
time_mask = "M73 P%s R%s\n";
break;
}
case Silent:
{
time_mask = "M73 Q%s S%s\n";
break;
}
}
std::string normal_time_mask = "M73 P%s R%s\n";
std::string silent_time_mask = "M73 Q%s S%s\n";
char line_M73[64];
unsigned int g1_lines_count = 0;
float last_recorded_time = 0.0f;
std::string gcode_line;
// buffer line to export only when greater than 64K to reduce writing calls
std::string export_line;
char time_line[64];
G1LineIdToBlockIdMap::const_iterator it_line_id = m_g1_line_ids.begin();
while (std::getline(in, gcode_line))
{
if (!in.good())
{
fclose(out);
throw std::runtime_error(std::string("Remaining times export failed.\nError while reading from file.\n"));
}
// replaces placeholders for initial line M73 with the real lines
if (((m_mode == Normal) && (gcode_line == Normal_First_M73_Output_Placeholder_Tag)) ||
((m_mode == Silent) && (gcode_line == Silent_First_M73_Output_Placeholder_Tag)))
{
sprintf(time_line, time_mask.c_str(), "0", _get_time_minutes(m_time).c_str());
gcode_line = time_line;
}
// replaces placeholders for final line M73 with the real lines
else if (((m_mode == Normal) && (gcode_line == Normal_Last_M73_Output_Placeholder_Tag)) ||
((m_mode == Silent) && (gcode_line == Silent_Last_M73_Output_Placeholder_Tag)))
{
sprintf(time_line, time_mask.c_str(), "100", "0");
gcode_line = time_line;
}
else
gcode_line += "\n";
// add remaining time lines where needed
m_parser.parse_line(gcode_line,
[this, &it_line_id, &g1_lines_count, &last_recorded_time, &time_line, &gcode_line, time_mask, interval](GCodeReader& reader, const GCodeReader::GCodeLine& line)
{
if (line.cmd_is("G1"))
{
++g1_lines_count;
assert(it_line_id == m_g1_line_ids.end() || it_line_id->first >= g1_lines_count);
const Block *block = nullptr;
if (it_line_id != m_g1_line_ids.end() && it_line_id->first == g1_lines_count) {
if (line.has_e() && it_line_id->second < (unsigned int)m_blocks.size())
block = &m_blocks[it_line_id->second];
++it_line_id;
}
if (block != nullptr && block->elapsed_time != -1.0f) {
float block_remaining_time = m_time - block->elapsed_time;
if (std::abs(last_recorded_time - block_remaining_time) > interval)
{
sprintf(time_line, time_mask.c_str(), std::to_string((int)(100.0f * block->elapsed_time / m_time)).c_str(), _get_time_minutes(block_remaining_time).c_str());
gcode_line += time_line;
last_recorded_time = block_remaining_time;
}
}
}
});
export_line += gcode_line;
if (export_line.length() > 65535)
{
fwrite((const void*)export_line.c_str(), 1, export_line.length(), out);
if (ferror(out))
{
in.close();
fclose(out);
boost::nowide::remove(path_tmp.c_str());
throw std::runtime_error(std::string("Remaining times export failed.\nIs the disk full?\n"));
}
export_line.clear();
}
}
if (export_line.length() > 0)
{
// helper function to write to disk
auto write_string = [&](const std::string& str) {
fwrite((const void*)export_line.c_str(), 1, export_line.length(), out);
if (ferror(out))
{
in.close();
fclose(out);
boost::nowide::remove(path_tmp.c_str());
throw std::runtime_error(std::string("Remaining times export failed.\nIs the disk full?\n"));
throw std::runtime_error(std::string("Time estimator post process export failed.\nIs the disk full?\n"));
}
export_line.clear();
};
GCodeReader parser;
unsigned int g1_lines_count = 0;
int normal_g1_line_id = 0;
float normal_last_recorded_time = 0.0f;
int silent_g1_line_id = 0;
float silent_last_recorded_time = 0.0f;
// helper function to process g1 lines
auto process_g1_line = [&](const PostProcessData* const data, const GCodeReader::GCodeLine& line, int& g1_line_id, float& last_recorded_time, const std::string& time_mask) {
if (data == nullptr)
return;
assert((g1_line_id >= (int)data->g1_line_ids.size()) || (data->g1_line_ids[g1_line_id].first >= g1_lines_count));
const Block* block = nullptr;
const G1LineIdToBlockId& map_item = data->g1_line_ids[g1_line_id];
if ((g1_line_id < (int)data->g1_line_ids.size()) && (map_item.first == g1_lines_count))
{
if (line.has_e() && (map_item.second < (unsigned int)data->blocks.size()))
block = &data->blocks[map_item.second];
++g1_line_id;
}
if ((block != nullptr) && (block->elapsed_time != -1.0f))
{
float block_remaining_time = data->time - block->elapsed_time;
if (std::abs(last_recorded_time - block_remaining_time) > interval_sec)
{
sprintf(line_M73, time_mask.c_str(), std::to_string((int)(100.0f * block->elapsed_time / data->time)).c_str(), _get_time_minutes(block_remaining_time).c_str());
gcode_line += line_M73;
last_recorded_time = block_remaining_time;
}
}
};
while (std::getline(in, gcode_line))
{
if (!in.good())
{
fclose(out);
throw std::runtime_error(std::string("Time estimator post process export failed.\nError while reading from file.\n"));
}
// check tags
// remove color change tag
if (gcode_line == "; " + Color_Change_Tag)
continue;
// replaces placeholders for initial line M73 with the real lines
if ((normal_mode != nullptr) && (gcode_line == Normal_First_M73_Output_Placeholder_Tag))
{
sprintf(line_M73, normal_time_mask.c_str(), "0", _get_time_minutes(normal_mode->time).c_str());
gcode_line = line_M73;
}
else if ((silent_mode != nullptr) && (gcode_line == Silent_First_M73_Output_Placeholder_Tag))
{
sprintf(line_M73, silent_time_mask.c_str(), "0", _get_time_minutes(silent_mode->time).c_str());
gcode_line = line_M73;
}
// replaces placeholders for final line M73 with the real lines
else if ((normal_mode != nullptr) && (gcode_line == Normal_Last_M73_Output_Placeholder_Tag))
{
sprintf(line_M73, normal_time_mask.c_str(), "100", "0");
gcode_line = line_M73;
}
else if ((silent_mode != nullptr) && (gcode_line == Silent_Last_M73_Output_Placeholder_Tag))
{
sprintf(line_M73, silent_time_mask.c_str(), "100", "0");
gcode_line = line_M73;
}
else
gcode_line += "\n";
// add remaining time lines where needed
parser.parse_line(gcode_line,
[&](GCodeReader& reader, const GCodeReader::GCodeLine& line)
{
if (line.cmd_is("G1"))
{
++g1_lines_count;
process_g1_line(silent_mode, line, silent_g1_line_id, silent_last_recorded_time, silent_time_mask);
process_g1_line(normal_mode, line, normal_g1_line_id, normal_last_recorded_time, normal_time_mask);
}
});
export_line += gcode_line;
if (export_line.length() > 65535)
write_string(export_line);
}
if (!export_line.empty())
write_string(export_line);
fclose(out);
in.close();
if (rename_file(path_tmp, filename))
throw std::runtime_error(std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + filename + '\n' +
"Is " + path_tmp + " locked?" + '\n');
"Is " + path_tmp + " locked?" + '\n');
return true;
}

View File

@ -213,9 +213,19 @@ namespace Slic3r {
typedef std::map<Block::EMoveType, MoveStats> MovesStatsMap;
#endif // ENABLE_MOVE_STATS
public:
typedef std::pair<unsigned int, unsigned int> G1LineIdToBlockId;
typedef std::vector<G1LineIdToBlockId> G1LineIdToBlockIdMap;
struct PostProcessData
{
const G1LineIdToBlockIdMap& g1_line_ids;
const BlocksList& blocks;
float time;
PostProcessData(const G1LineIdToBlockIdMap& g1_line_ids, const BlocksList& blocks, float time) : g1_line_ids(g1_line_ids), blocks(blocks), time(time) {}
};
private:
EMode m_mode;
GCodeReader m_parser;
@ -263,11 +273,12 @@ namespace Slic3r {
void calculate_time_from_lines(const std::vector<std::string>& gcode_lines);
// Process the gcode contained in the file with the given filename,
// placing in it new lines (M73) containing the remaining time, at the given interval in seconds
// and saving the result back in the same file
// This time estimator should have been already used to calculate the time estimate for the gcode
// contained in the given file before to call this method
bool post_process_remaining_times(const std::string& filename, float interval_sec);
// replacing placeholders with correspondent new lines M73
// placing new lines M73 (containing the remaining time) where needed (in dependence of the given interval in seconds)
// and removing working tags (as those used for color changes)
// if normal_mode == nullptr no M73 line will be added for normal mode
// if silent_mode == nullptr no M73 line will be added for silent mode
static bool post_process(const std::string& filename, float interval_sec, const PostProcessData* const normal_mode, const PostProcessData* const silent_mode);
// Set current position on the given axis with the given value
void set_axis_position(EAxis axis, float position);
@ -362,6 +373,8 @@ namespace Slic3r {
// Return an estimate of the memory consumed by the time estimator.
size_t memory_used() const;
PostProcessData get_post_process_data() const { return PostProcessData(m_g1_line_ids, m_blocks, m_time); }
private:
void _reset();
void _reset_time();

View File

@ -171,21 +171,6 @@ void Layer::make_perimeters()
BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id() << " - Done";
}
void Layer::make_fills()
{
#ifdef SLIC3R_DEBUG
printf("Making fills for layer " PRINTF_ZU "\n", this->id());
#endif
for (LayerRegion *layerm : m_regions) {
layerm->fills.clear();
make_fill(*layerm, layerm->fills);
#ifndef NDEBUG
for (size_t i = 0; i < layerm->fills.entities.size(); ++ i)
assert(dynamic_cast<ExtrusionEntityCollection*>(layerm->fills.entities[i]) != NULL);
#endif
}
}
void Layer::export_region_slices_to_svg(const char *path) const
{
BoundingBox bbox;

View File

@ -74,7 +74,7 @@ public:
config(config), object_config(object_config), print_config(print_config),
loops(loops), gap_fill(gap_fill), fill_surfaces(fill_surfaces),
_ext_mm3_per_mm(-1), _mm3_per_mm(-1), _mm3_per_mm_overhang(-1)
{};
{}
void process();
private:

View File

@ -108,7 +108,6 @@ static inline bool opts_equal(const DynamicConfig &config_old, const DynamicConf
std::vector<std::string> PlaceholderParser::config_diff(const DynamicPrintConfig &rhs)
{
const ConfigDef *def = rhs.def();
std::vector<std::string> diff_keys;
for (const t_config_option_key &opt_key : rhs.keys())
if (! opts_equal(m_config, rhs, opt_key))
@ -124,7 +123,6 @@ std::vector<std::string> PlaceholderParser::config_diff(const DynamicPrintConfig
// a current extruder ID is used.
bool PlaceholderParser::apply_config(const DynamicPrintConfig &rhs)
{
const ConfigDef *def = rhs.def();
bool modified = false;
for (const t_config_option_key &opt_key : rhs.keys()) {
if (! opts_equal(m_config, rhs, opt_key)) {

View File

@ -1228,24 +1228,35 @@ std::string Print::validate() const
if (has_custom_layering) {
const std::vector<coordf_t> &layer_height_profile_tallest = layer_height_profiles[tallest_object_idx];
for (size_t idx_object = 0; idx_object < m_objects.size(); ++ idx_object) {
if (idx_object == tallest_object_idx)
continue;
const std::vector<coordf_t> &layer_height_profile = layer_height_profiles[idx_object];
bool failed = false;
if (layer_height_profile_tallest.size() >= layer_height_profile.size()) {
size_t i = 0;
while (i < layer_height_profile.size() && i < layer_height_profile_tallest.size()) {
if (std::abs(layer_height_profile_tallest[i] - layer_height_profile[i])) {
failed = true;
break;
}
++ i;
if (i == layer_height_profile.size() - 2) // this element contains this objects max z
if (layer_height_profile_tallest[i] > layer_height_profile[i]) // the difference does not matter in this case
++ i;
// The comparison of the profiles is not just about element-wise equality, some layers may not be
// explicitely included. Always remember z and height of last reference layer that in the vector
// and compare to that.
size_t i = 0; // index into tested profile
size_t j = 0; // index into reference profile
coordf_t ref_z = -1.;
coordf_t next_ref_z = layer_height_profile_tallest[0];
coordf_t ref_height = -1.;
while (i < layer_height_profile.size()) {
coordf_t this_z = layer_height_profile[i];
coordf_t this_height = layer_height_profile[i+1];
if (next_ref_z < this_z + EPSILON) {
ref_z = next_ref_z;
do { // one layer can be in the vector several times
ref_height = layer_height_profile_tallest[j+1];
if (j+2 >= layer_height_profile_tallest.size())
break;
j += 2;
next_ref_z = layer_height_profile_tallest[j];
} while (ref_z == next_ref_z);
}
} else
failed = true;
if (failed)
return L("The Wipe tower is only supported if all objects have the same layer height profile");
if (std::abs(this_height - ref_height) > EPSILON)
return L("The Wipe tower is only supported if all objects have the same layer height profile");
i += 2;
}
}
}
}

View File

@ -39,6 +39,8 @@ class PrintRegion
public:
const Print* print() const { return m_print; }
const PrintRegionConfig& config() const { return m_config; }
// 1-based extruder identifier for this region and role.
unsigned int extruder(FlowRole role) const;
Flow flow(FlowRole role, double layer_height, bool bridge, bool first_layer, double width, const PrintObject &object) const;
// Average diameter of nozzles participating on extruding this region.
coordf_t nozzle_dmr_avg(const PrintConfig &print_config) const;

View File

@ -2049,7 +2049,7 @@ void PrintConfigDef::init_fff_params()
{
int threads = (unsigned int)boost::thread::hardware_concurrency();
def->set_default_value(new ConfigOptionInt(threads > 0 ? threads : 2));
def->cli == ConfigOptionDef::nocli;
def->cli = ConfigOptionDef::nocli;
}
def = this->add("toolchange_gcode", coString);

View File

@ -24,7 +24,7 @@
namespace Slic3r {
enum GCodeFlavor {
enum GCodeFlavor : unsigned char {
gcfRepRap, gcfRepetier, gcfTeacup, gcfMakerWare, gcfMarlin, gcfSailfish, gcfMach3, gcfMachinekit,
gcfSmoothie, gcfNoExtrusion,
};
@ -35,7 +35,7 @@ enum PrintHostType {
enum InfillPattern {
ipRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral,
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipCount,
};
enum SupportMaterialPattern {

View File

@ -1443,11 +1443,8 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c
layer_height_profile.clear();
if (layer_height_profile.empty()) {
if (0)
// if (this->layer_height_profile.empty())
layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_config_ranges, model_object.volumes);
else
layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges); // #ys_FIXME_experiment
//layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_config_ranges, model_object.volumes);
layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges);
updated = true;
}
return updated;
@ -1870,12 +1867,13 @@ std::vector<ExPolygons> PrintObject::slice_modifiers(size_t region_id, const std
merge.assign(out.size(), false);
} else {
for (size_t i = 0; i < out.size(); ++ i)
if (! this_slices[i].empty())
if (! this_slices[i].empty()) {
if (! out[i].empty()) {
append(out[i], this_slices[i]);
merge[i] = true;
} else
out[i] = std::move(this_slices[i]);
}
}
i = j;
} else

View File

@ -2,6 +2,21 @@
namespace Slic3r {
// 1-based extruder identifier for this region and role.
unsigned int PrintRegion::extruder(FlowRole role) const
{
size_t extruder = 0;
if (role == frPerimeter || role == frExternalPerimeter)
extruder = m_config.perimeter_extruder;
else if (role == frInfill)
extruder = m_config.infill_extruder;
else if (role == frSolidInfill || role == frTopSolidInfill)
extruder = m_config.solid_infill_extruder;
else
throw std::invalid_argument("Unknown role");
return extruder;
}
Flow PrintRegion::flow(FlowRole role, double layer_height, bool bridge, bool first_layer, double width, const PrintObject &object) const
{
ConfigOptionFloatOrPercent config_width;
@ -28,24 +43,13 @@ Flow PrintRegion::flow(FlowRole role, double layer_height, bool bridge, bool fir
throw std::invalid_argument("Unknown role");
}
}
if (config_width.value == 0) {
if (config_width.value == 0)
config_width = object.config().extrusion_width;
}
// get the configured nozzle_diameter for the extruder associated
// to the flow role requested
size_t extruder = 0; // 1-based
if (role == frPerimeter || role == frExternalPerimeter) {
extruder = m_config.perimeter_extruder;
} else if (role == frInfill) {
extruder = m_config.infill_extruder;
} else if (role == frSolidInfill || role == frTopSolidInfill) {
extruder = m_config.solid_infill_extruder;
} else {
throw std::invalid_argument("Unknown role");
}
double nozzle_diameter = m_print->config().nozzle_diameter.get_at(extruder-1);
// Get the configured nozzle_diameter for the extruder associated to the flow role requested.
// Here this->extruder(role) - 1 may underflow to MAX_INT, but then the get_at() will follback to zero'th element, so everything is all right.
double nozzle_diameter = m_print->config().nozzle_diameter.get_at(this->extruder(role) - 1);
return Flow::new_from_config_width(role, config_width, (float)nozzle_diameter, (float)layer_height, bridge ? (float)m_config.bridge_flow_ratio : 0.0f);
}
@ -79,12 +83,14 @@ void PrintRegion::collect_object_printing_extruders(const PrintConfig &print_con
void PrintRegion::collect_object_printing_extruders(std::vector<unsigned int> &object_extruders) const
{
auto num_extruders = (int)print()->config().nozzle_diameter.size();
// PrintRegion, if used by some PrintObject, shall have all the extruders set to an existing printer extruder.
// If not, then there must be something wrong with the Print::apply() function.
#ifndef NDEBUG
auto num_extruders = (int)print()->config().nozzle_diameter.size();
assert(this->config().perimeter_extruder <= num_extruders);
assert(this->config().infill_extruder <= num_extruders);
assert(this->config().solid_infill_extruder <= num_extruders);
#endif
collect_object_printing_extruders(print()->config(), this->config(), object_extruders);
}

View File

@ -185,8 +185,6 @@ private:
SLAAutoSupports::Config m_config;
float m_supports_force_total = 0.f;
void process(const std::vector<ExPolygons>& slices, const std::vector<float>& heights);
void uniformly_cover(const ExPolygons& islands, Structure& structure, PointGrid3D &grid3d, bool is_new_island = false, bool just_one = false);
void project_onto_mesh(std::vector<sla::SupportPoint>& points) const;

View File

@ -676,7 +676,7 @@ std::string SLAPrint::validate() const
if(supports_en && !builtinpad.enabled && elv < pinhead_width )
return L(
"Elevation is too low for object. Use the \"Pad around "
"obect\" feature to print the object without elevation.");
"object\" feature to print the object without elevation.");
if(supports_en && builtinpad.enabled &&
cfg.pillar_base_safety_distance_mm < builtinpad.object_gap_mm) {

View File

@ -24,9 +24,8 @@ enum SurfaceType {
stInternalVoid,
// Inner/outer perimeters.
stPerimeter,
// Last surface type, if the SurfaceType is used as an index into a vector.
stLast,
stCount = stLast + 1
// Number of SurfaceType enums.
stCount,
};
class Surface

View File

@ -37,6 +37,7 @@ public:
void clear() { surfaces.clear(); }
bool empty() const { return surfaces.empty(); }
size_t size() const { return surfaces.size(); }
bool has(SurfaceType type) const {
for (const Surface &surface : this->surfaces)
if (surface.surface_type == type) return true;

View File

@ -1142,7 +1142,7 @@ void GLVolumeCollection::export_toolpaths_to_obj(const char* filename) const
Color color;
::memcpy((void*)color.data(), (const void*)volume->color, 4 * sizeof(float));
fprintf(fp, "\n# material volume %d\n", volumes_count);
fprintf(fp, "usemtl material_%lld\n", 1 + std::distance(colors.begin(), colors.find(color)));
fprintf(fp, "usemtl material_%lld\n", (long long)(1 + std::distance(colors.begin(), colors.find(color))));
int base_vertex_id = vertices_count + 1;
int base_normal_id = normals_count + 1;
@ -1242,8 +1242,8 @@ static void thick_lines_to_indexed_vertex_array(
// calculate new XY normals
Vec2d xy_right_normal = unscale(line.normal()).normalized();
int idx_a[4];
int idx_b[4];
int idx_a[4] = { 0, 0, 0, 0 }; // initialized to avoid warnings
int idx_b[4] = { 0, 0, 0, 0 }; // initialized to avoid warnings
int idx_last = int(volume.vertices_and_normals_interleaved.size() / 6);
bool bottom_z_different = bottom_z_prev != bottom_z;

View File

@ -446,7 +446,7 @@ void BedShapePanel::update_shape()
auto twopi = 2 * PI;
auto edges = 72;
std::vector<Vec2d> points;
for (size_t i = 1; i <= edges; ++i) {
for (int i = 1; i <= edges; ++i) {
auto angle = i * twopi / edges;
points.push_back(Vec2d(r*cos(angle), r*sin(angle)));
}

View File

@ -197,7 +197,7 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
show_error(m_parent, _(L("Invalid numeric input.")));
set_value(double_to_string(val), true);
}
else if (check_value && (m_opt.sidetext.rfind("mm/s") != std::string::npos && val > m_opt.max ||
else if (check_value && ((m_opt.sidetext.rfind("mm/s") != std::string::npos && val > m_opt.max) ||
m_opt.sidetext.rfind("mm ") != std::string::npos && val > 1) &&
(m_value.empty() || std::string(str.ToUTF8().data()) != boost::any_cast<std::string>(m_value)))
{
@ -444,7 +444,7 @@ void TextCtrl::disable() { dynamic_cast<wxTextCtrl*>(window)->Disable(); dynamic
#ifdef __WXGTK__
void TextCtrl::change_field_value(wxEvent& event)
{
if (bChangedValueEvent = event.GetEventType()==wxEVT_KEY_UP)
if (bChangedValueEvent = (event.GetEventType()==wxEVT_KEY_UP))
on_change_field();
event.Skip();
};
@ -768,7 +768,7 @@ void Choice::set_selection()
size_t idx = 0;
for (auto el : m_opt.enum_values)
{
if (el.compare(text_value) == 0)
if (el == text_value)
break;
++idx;
}
@ -789,7 +789,7 @@ void Choice::set_selection()
size_t idx = 0;
for (auto el : m_opt.enum_values)
{
if (el.compare(text_value) == 0)
if (el == text_value)
break;
++idx;
}
@ -804,7 +804,7 @@ void Choice::set_selection()
size_t idx = 0;
for (auto el : m_opt.enum_values)
{
if (el.compare(text_value) == 0)
if (el == text_value)
break;
++idx;
}
@ -813,6 +813,7 @@ void Choice::set_selection()
field->SetSelection(idx);
break;
}
default: break;
}
}
@ -823,7 +824,7 @@ void Choice::set_value(const std::string& value, bool change_event) //! Redunda
size_t idx=0;
for (auto el : m_opt.enum_values)
{
if (el.compare(value) == 0)
if (el == value)
break;
++idx;
}
@ -856,7 +857,7 @@ void Choice::set_value(const boost::any& value, bool change_event)
auto idx = 0;
for (auto el : m_opt.enum_values)
{
if (el.compare(text_value) == 0)
if (el == text_value)
break;
++idx;
}
@ -887,7 +888,7 @@ void Choice::set_value(const boost::any& value, bool change_event)
size_t idx = 0;
for (auto el : m_opt.enum_values)
{
if (el.compare(key) == 0)
if (el == key)
break;
++idx;
}

View File

@ -845,22 +845,23 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_values(const GCodePrevie
{
auto& config = wxGetApp().preset_bundle->project_config;
const std::vector<double>& color_print_values = config.option<ConfigOptionFloats>("colorprint_heights")->values;
const size_t values_cnt = color_print_values.size();
if (values_cnt > 0) {
if (!color_print_values.empty()) {
std::vector<double> print_zs = canvas.get_current_print_zs(true);
size_t z = 0;
for (size_t i = 0; i < values_cnt; ++i)
for (auto cp_value : color_print_values)
{
double prev_z = -1.0;
for ( ; z < print_zs.size(); ++z)
if (fabs(color_print_values[i] - print_zs[z]) < EPSILON) {
prev_z = z > 0 ? print_zs[z - 1] : 0.;
break;
}
if (prev_z < 0)
auto lower_b = std::lower_bound(print_zs.begin(), print_zs.end(), cp_value - DoubleSlider::epsilon());
if (lower_b == print_zs.end())
continue;
cp_legend_values.push_back(std::pair<double, double>(prev_z, color_print_values[i]));
double current_z = *lower_b;
double previous_z = lower_b == print_zs.begin() ? 0.0 : *(--lower_b);
// to avoid duplicate values, check adding values
if (cp_legend_values.empty() ||
!(cp_legend_values.back().first == previous_z && cp_legend_values.back().second == current_z) )
cp_legend_values.push_back(std::pair<double, double>(previous_z, current_z));
}
}
}
@ -901,11 +902,11 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
// Disabling ClearType works, but the font returned is very different (much thicker) from the default.
// msw_disable_cleartype(font);
bool cleartype = is_font_cleartype(font);
// bool cleartype = is_font_cleartype(font);
#else
// select default font
wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Scale(scale_gl);
bool cleartype = false;
// bool cleartype = false;
#endif /* __WXMSW__ */
memDC.SetFont(font);
@ -1330,13 +1331,13 @@ void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject
void GLCanvas3D::update_instance_printable_state_for_object(const size_t obj_idx)
{
ModelObject* model_object = m_model->objects[obj_idx];
for (int inst_idx = 0; inst_idx < model_object->instances.size(); inst_idx++)
for (int inst_idx = 0; inst_idx < (int)model_object->instances.size(); ++inst_idx)
{
ModelInstance* instance = model_object->instances[inst_idx];
for (GLVolume* volume : m_volumes.volumes)
{
if ((volume->object_idx() == obj_idx) && (volume->instance_idx() == inst_idx))
if ((volume->object_idx() == (int)obj_idx) && (volume->instance_idx() == inst_idx))
volume->printable = instance->printable;
}
}
@ -1672,7 +1673,7 @@ void GLCanvas3D::ensure_on_bed(unsigned int object_idx)
for (GLVolume* volume : m_volumes.volumes)
{
if ((volume->object_idx() == object_idx) && !volume->is_modifier)
if ((volume->object_idx() == (int)object_idx) && !volume->is_modifier)
{
double min_z = volume->transformed_convex_hull_bounding_box().min(2);
std::pair<int, int> instance = std::make_pair(volume->object_idx(), volume->instance_idx());
@ -1968,8 +1969,8 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
}
}
// stores the current volumes count
size_t volumes_count = m_volumes.volumes.size();
// // stores the current volumes count
// size_t volumes_count = m_volumes.volumes.size();
for (size_t istep = 0; istep < sla_steps.size(); ++istep)
if (!instances[istep].empty())
@ -1978,7 +1979,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
// Shift-up all volumes of the object so that it has the right elevation with respect to the print bed
for (GLVolume* volume : m_volumes.volumes)
if (volume->object_idx() < m_model->objects.size() && m_model->objects[volume->object_idx()]->instances[volume->instance_idx()]->is_printable())
if (volume->object_idx() < (int)m_model->objects.size() && m_model->objects[volume->object_idx()]->instances[volume->instance_idx()]->is_printable())
volume->set_sla_shift_z(shift_zs[volume->object_idx()]);
}
@ -3733,7 +3734,7 @@ bool GLCanvas3D::_init_undoredo_toolbar()
item.right.render_callback = [this](float left, float right, float, float) { if (m_canvas != nullptr) _render_undo_redo_stack(true, 0.5f * (left + right)); };
item.enabling_callback = [this]()->bool {
bool can_undo = wxGetApp().plater()->can_undo();
unsigned int id = m_undoredo_toolbar.get_item_id("undo");
int id = m_undoredo_toolbar.get_item_id("undo");
std::string curr_additional_tooltip;
m_undoredo_toolbar.get_additional_tooltip(id, curr_additional_tooltip);
@ -3765,7 +3766,7 @@ bool GLCanvas3D::_init_undoredo_toolbar()
item.right.render_callback = [this](float left, float right, float, float) { if (m_canvas != nullptr) _render_undo_redo_stack(false, 0.5f * (left + right)); };
item.enabling_callback = [this]()->bool {
bool can_redo = wxGetApp().plater()->can_redo();
unsigned int id = m_undoredo_toolbar.get_item_id("redo");
int id = m_undoredo_toolbar.get_item_id("redo");
std::string curr_additional_tooltip;
m_undoredo_toolbar.get_additional_tooltip(id, curr_additional_tooltip);
@ -3908,7 +3909,7 @@ void GLCanvas3D::_picking_pass() const
m_gizmos.set_hover_id(-1);
}
else
m_gizmos.set_hover_id(inside && volume_id <= GLGizmoBase::BASE_ID ? (GLGizmoBase::BASE_ID - volume_id) : -1);
m_gizmos.set_hover_id(inside && volume_id <= (int)GLGizmoBase::BASE_ID ? ((int)GLGizmoBase::BASE_ID - volume_id) : -1);
_update_volumes_hover_state();
}
@ -4858,7 +4859,7 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_
ctxt.print = print;
ctxt.tool_colors = tool_colors.empty() ? nullptr : &tool_colors;
if (print->wipe_tower_data().priming && print->config().single_extruder_multi_material_priming)
for (int i=0; i<print->wipe_tower_data().priming.get()->size(); ++i)
for (int i=0; i<(int)print->wipe_tower_data().priming.get()->size(); ++i)
ctxt.priming.emplace_back(print->wipe_tower_data().priming.get()->at(i));
if (print->wipe_tower_data().final_purge)
ctxt.final.emplace_back(*print->wipe_tower_data().final_purge.get());
@ -5037,7 +5038,7 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
}
case GCodePreviewData::Extrusion::ColorPrint:
{
const size_t color_cnt = tool_colors.size() / 4;
int color_cnt = (int)tool_colors.size() / 4;
int val = int(value);
while (val >= color_cnt)

View File

@ -641,11 +641,9 @@ public:
void start_keeping_dirty() { m_keep_dirty = true; }
void stop_keeping_dirty() { m_keep_dirty = false; }
unsigned int get_main_toolbar_item_id(const std::string& name) const { return m_main_toolbar.get_item_id(name); }
void force_main_toolbar_left_action(unsigned int item_id) { m_main_toolbar.force_left_action(item_id, *this); }
void force_main_toolbar_right_action(unsigned int item_id) { m_main_toolbar.force_right_action(item_id, *this); }
void get_undoredo_toolbar_additional_tooltip(unsigned int item_id, std::string& text) { return m_undoredo_toolbar.get_additional_tooltip(item_id, text); }
void set_undoredo_toolbar_additional_tooltip(unsigned int item_id, const std::string& text) { m_undoredo_toolbar.set_additional_tooltip(item_id, text); }
int get_main_toolbar_item_id(const std::string& name) const { return m_main_toolbar.get_item_id(name); }
void force_main_toolbar_left_action(int item_id) { m_main_toolbar.force_left_action(item_id, *this); }
void force_main_toolbar_right_action(int item_id) { m_main_toolbar.force_right_action(item_id, *this); }
bool has_toolpaths_to_export() const;
void export_toolpaths_to_obj(const char* filename) const;

View File

@ -359,9 +359,7 @@ bool GLCanvas3DManager::init(GLCanvas3D& canvas)
void GLCanvas3DManager::detect_multisample(int* attribList)
{
int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER;
const AppConfig* app_config = GUI::get_app_config();
bool enable_multisample = wxVersion >= 30003;
s_multisample = (enable_multisample && wxGLCanvas::IsDisplaySupported(attribList)) ? MS_Enabled : MS_Disabled;
// Alternative method: it was working on previous version of wxWidgets but not with the latest, at least on Windows
// s_multisample = enable_multisample && wxGLCanvas::IsExtensionSupported("WGL_ARB_multisample");

View File

@ -56,7 +56,7 @@ bool GLTexture::Compressor::unsent_compressed_data_available() const
{
if (m_levels.empty())
return false;
// Querying the atomic m_num_levels_compressed value synchronizes processor caches, so that the dat of m_levels modified by the worker thread are accessible to the calling thread.
// Querying the atomic m_num_levels_compressed value synchronizes processor caches, so that the data of m_levels modified by the worker thread are accessible to the calling thread.
unsigned int num_compressed = m_num_levels_compressed;
for (unsigned int i = 0; i < num_compressed; ++ i)
if (! m_levels[i].sent_to_gpu && ! m_levels[i].compressed_data.empty())
@ -89,8 +89,8 @@ void GLTexture::Compressor::send_compressed_data_to_gpu()
}
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
if (num_compressed == (unsigned int)m_levels.size())
// Finalize the worker thread, close it.
if (num_compressed == (int)m_levels.size())
// Finalize the worker thread, close it.
this->reset();
}

View File

@ -345,9 +345,9 @@ bool GLToolbar::is_any_item_pressed() const
return false;
}
unsigned int GLToolbar::get_item_id(const std::string& name) const
int GLToolbar::get_item_id(const std::string& name) const
{
for (unsigned int i = 0; i < (unsigned int)m_items.size(); ++i)
for (int i = 0; i < (int)m_items.size(); ++i)
{
if (m_items[i]->get_name() == name)
return i;
@ -356,19 +356,9 @@ unsigned int GLToolbar::get_item_id(const std::string& name) const
return -1;
}
void GLToolbar::force_left_action(unsigned int item_id, GLCanvas3D& parent)
void GLToolbar::get_additional_tooltip(int item_id, std::string& text)
{
do_action(GLToolbarItem::Left, item_id, parent, false);
}
void GLToolbar::force_right_action(unsigned int item_id, GLCanvas3D& parent)
{
do_action(GLToolbarItem::Right, item_id, parent, false);
}
void GLToolbar::get_additional_tooltip(unsigned int item_id, std::string& text)
{
if (item_id < (unsigned int)m_items.size())
if ((0 <= item_id) && (item_id < (int)m_items.size()))
{
GLToolbarItem* item = m_items[item_id];
if (item != nullptr)
@ -381,9 +371,9 @@ void GLToolbar::get_additional_tooltip(unsigned int item_id, std::string& text)
text = L("");
}
void GLToolbar::set_additional_tooltip(unsigned int item_id, const std::string& text)
void GLToolbar::set_additional_tooltip(int item_id, const std::string& text)
{
if (item_id < (unsigned int)m_items.size())
if ((0 <= item_id) && (item_id < (int)m_items.size()))
{
GLToolbarItem* item = m_items[item_id];
if (item != nullptr)
@ -466,7 +456,7 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
if ((item_id != -2) && !m_items[item_id]->is_separator() && ((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Left)))
{
// mouse is inside an icon
do_action(GLToolbarItem::Left, (unsigned int)item_id, parent, true);
do_action(GLToolbarItem::Left, item_id, parent, true);
parent.set_as_dirty();
}
}
@ -483,7 +473,7 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
if ((item_id != -2) && !m_items[item_id]->is_separator() && ((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Right)))
{
// mouse is inside an icon
do_action(GLToolbarItem::Right, (unsigned int)item_id, parent, true);
do_action(GLToolbarItem::Right, item_id, parent, true);
parent.set_as_dirty();
}
}
@ -556,11 +546,11 @@ float GLToolbar::get_main_size() const
return size * m_layout.scale;
}
void GLToolbar::do_action(GLToolbarItem::EActionType type, unsigned int item_id, GLCanvas3D& parent, bool check_hover)
void GLToolbar::do_action(GLToolbarItem::EActionType type, int item_id, GLCanvas3D& parent, bool check_hover)
{
if ((m_pressed_toggable_id == -1) || (m_pressed_toggable_id == item_id))
{
if (item_id < (unsigned int)m_items.size())
if ((0 <= item_id) && (item_id < (int)m_items.size()))
{
GLToolbarItem* item = m_items[item_id];
if ((item != nullptr) && !item->is_separator() && (!check_hover || item->is_hovered()))
@ -1246,7 +1236,7 @@ bool GLToolbar::update_items_enabled_state()
{
bool ret = false;
for (unsigned int i = 0; i < (unsigned int)m_items.size(); ++i)
for (int i = 0; i < (int)m_items.size(); ++i)
{
GLToolbarItem* item = m_items[i];
ret |= item->update_enabled_state();

View File

@ -254,7 +254,7 @@ private:
MouseCapture m_mouse_capture;
std::string m_tooltip;
unsigned int m_pressed_toggable_id;
int m_pressed_toggable_id;
public:
GLToolbar(EType type, const std::string& name);
@ -293,15 +293,15 @@ public:
bool is_any_item_pressed() const;
unsigned int get_item_id(const std::string& name) const;
int get_item_id(const std::string& name) const;
void force_left_action(unsigned int item_id, GLCanvas3D& parent);
void force_right_action(unsigned int item_id, GLCanvas3D& parent);
void force_left_action(int item_id, GLCanvas3D& parent) { do_action(GLToolbarItem::Left, item_id, parent, false); }
void force_right_action(int item_id, GLCanvas3D& parent) { do_action(GLToolbarItem::Right, item_id, parent, false); }
const std::string& get_tooltip() const { return m_tooltip; }
void get_additional_tooltip(unsigned int item_id, std::string& text);
void set_additional_tooltip(unsigned int item_id, const std::string& text);
void get_additional_tooltip(int item_id, std::string& text);
void set_additional_tooltip(int item_id, const std::string& text);
// returns true if any item changed its state
bool update_items_state();
@ -317,7 +317,7 @@ private:
float get_height_horizontal() const;
float get_height_vertical() const;
float get_main_size() const;
void do_action(GLToolbarItem::EActionType type, unsigned int item_id, GLCanvas3D& parent, bool check_hover);
void do_action(GLToolbarItem::EActionType type, int item_id, GLCanvas3D& parent, bool check_hover);
std::string update_hover_state(const Vec2d& mouse_pos, GLCanvas3D& parent);
std::string update_hover_state_horizontal(const Vec2d& mouse_pos, GLCanvas3D& parent);
std::string update_hover_state_vertical(const Vec2d& mouse_pos, GLCanvas3D& parent);

View File

@ -262,7 +262,7 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt
}
catch (const std::exception & /* e */)
{
int i = 0;//no reason, just experiment
// int i = 0;//no reason, just experiment
}
}

View File

@ -302,8 +302,9 @@ bool GUI_App::on_init_inner()
* change min hight of object list to the normal min value (15 * wxGetApp().em_unit())
* after first whole Mainframe updating/layouting
*/
if (obj_list()->GetMinSize().GetY() > 15 * em_unit())
obj_list()->SetMinSize(wxSize(-1, 15 * em_unit()));
const int list_min_height = 15 * em_unit();
if (obj_list()->GetMinSize().GetY() > list_min_height)
obj_list()->SetMinSize(wxSize(-1, list_min_height));
update_mode(); // update view mode after fix of the object_list size
@ -474,8 +475,9 @@ void GUI_App::recreate_GUI()
* change min hight of object list to the normal min value (15 * wxGetApp().em_unit())
* after first whole Mainframe updating/layouting
*/
if (obj_list()->GetMinSize().GetY() > 15 * em_unit())
obj_list()->SetMinSize(wxSize(-1, 15 * em_unit()));
const int list_min_height = 15 * em_unit();
if (obj_list()->GetMinSize().GetY() > list_min_height)
obj_list()->SetMinSize(wxSize(-1, list_min_height));
update_mode();
@ -908,11 +910,13 @@ bool GUI_App::check_unsaved_changes(const wxString &header)
wxString dirty;
PrinterTechnology printer_technology = preset_bundle->printers.get_edited_preset().printer_technology();
for (Tab *tab : tabs_list)
if (tab->supports_printer_technology(printer_technology) && tab->current_preset_is_dirty())
if (tab->supports_printer_technology(printer_technology) && tab->current_preset_is_dirty()) {
if (dirty.empty())
dirty = tab->title();
else
dirty += wxString(", ") + tab->title();
}
if (dirty.empty())
// No changes, the application may close or reload presets.
return true;
@ -1085,7 +1089,7 @@ void GUI_App::window_pos_restore(wxTopLevelWindow* window, const std::string &na
void GUI_App::window_pos_sanitize(wxTopLevelWindow* window)
{
unsigned display_idx = wxDisplay::GetFromWindow(window);
/*unsigned*/int display_idx = wxDisplay::GetFromWindow(window);
wxRect display;
if (display_idx == wxNOT_FOUND) {
display = wxDisplay(0u).GetClientArea();

View File

@ -29,7 +29,7 @@ namespace GUI
wxDEFINE_EVENT(EVT_OBJ_LIST_OBJECT_SELECT, SimpleEvent);
// pt_FFF
SettingsBundle FREQ_SETTINGS_BUNDLE_FFF =
static SettingsBundle FREQ_SETTINGS_BUNDLE_FFF =
{
{ L("Layers and Perimeters"), { "layer_height" , "perimeters", "top_solid_layers", "bottom_solid_layers" } },
{ L("Infill") , { "fill_density", "fill_pattern" } },
@ -40,13 +40,13 @@ SettingsBundle FREQ_SETTINGS_BUNDLE_FFF =
};
// pt_SLA
SettingsBundle FREQ_SETTINGS_BUNDLE_SLA =
static SettingsBundle FREQ_SETTINGS_BUNDLE_SLA =
{
{ L("Pad and Support") , { "supports_enable", "pad_enable" } }
};
// Note: id accords to type of the sub-object (adding volume), so sequence of the menu items is important
std::vector<std::pair<std::string, std::string>> ADD_VOLUME_MENU_ITEMS = {
static std::vector<std::pair<std::string, std::string>> ADD_VOLUME_MENU_ITEMS = {
// menu_item Name menu_item bitmap name
{L("Add part"), "add_part" }, // ~ModelVolumeType::MODEL_PART
{L("Add modifier"), "add_modifier"}, // ~ModelVolumeType::PARAMETER_MODIFIER
@ -126,7 +126,7 @@ ObjectList::ObjectList(wxWindow* parent) :
#ifdef __WXMSW__
// Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected.
int new_selected_column = -1;
#endif __WXMSW__
#endif //__WXMSW__
if (wxGetKeyState(WXK_SHIFT))
{
wxDataViewItemArray sels;
@ -149,12 +149,12 @@ ObjectList::ObjectList(wxWindow* parent) :
wxUIActionSimulator sim;
sim.Char(WXK_RETURN);
}
#endif __WXMSW__
#endif //__WXMSW__
m_last_selected_item = new_selected_item;
}
#ifdef __WXMSW__
m_last_selected_column = new_selected_column;
#endif __WXMSW__
#endif //__WXMSW__
selection_changed();
#ifndef __WXMSW__
@ -192,7 +192,7 @@ ObjectList::ObjectList(wxWindow* parent) :
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->undo(); }, wxID_UNDO);
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->redo(); }, wxID_REDO);
}
#else __WXOSX__
#else //__WXOSX__
Bind(wxEVT_CHAR, [this](wxKeyEvent& event) { key_event(event); }); // doesn't work on OSX
#endif
@ -281,9 +281,9 @@ void ObjectList::create_popup_menus()
create_instance_popupmenu(&m_menu_instance);
}
void ObjectList::get_selected_item_indexes(int& obj_idx, int& vol_idx, const wxDataViewItem& input_item/* = wxDataViewItem(0)*/)
void ObjectList::get_selected_item_indexes(int& obj_idx, int& vol_idx, const wxDataViewItem& input_item/* = wxDataViewItem(nullptr)*/)
{
const wxDataViewItem item = input_item == wxDataViewItem(0) ? GetSelection() : input_item;
const wxDataViewItem item = input_item == wxDataViewItem(nullptr) ? GetSelection() : input_item;
if (!item)
{
@ -737,7 +737,7 @@ void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& vol
if (items.size() > 1)
{
m_selection_mode = smVolume;
m_last_selected_item = wxDataViewItem(0);
m_last_selected_item = wxDataViewItem(nullptr);
}
select_items(items);
@ -844,7 +844,7 @@ void ObjectList::show_context_menu()
wxMenu* menu = type & itInstance ? &m_menu_instance :
type & itLayer ? &m_menu_layer :
m_objects_model->GetParent(item) != wxDataViewItem(0) ? &m_menu_part :
m_objects_model->GetParent(item) != wxDataViewItem(nullptr) ? &m_menu_part :
printer_technology() == ptFFF ? &m_menu_object : &m_menu_sla_object;
if (!(type & itInstance))
@ -915,9 +915,9 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event)
const bool mult_sel = multiple_selection();
if (mult_sel && !selected_instances_of_same_object() ||
!mult_sel && (GetSelection() != item ||
m_objects_model->GetParent(item) == wxDataViewItem(0) ) ) {
if ((mult_sel && !selected_instances_of_same_object()) ||
(!mult_sel && (GetSelection() != item)) ||
m_objects_model->GetParent(item) == wxDataViewItem(nullptr) ) {
event.Veto();
return;
}
@ -962,10 +962,10 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event)
bool ObjectList::can_drop(const wxDataViewItem& item) const
{
return m_dragged_data.type() == itInstance && !item.IsOk() ||
m_dragged_data.type() == itVolume && item.IsOk() &&
return (m_dragged_data.type() == itInstance && !item.IsOk()) ||
(m_dragged_data.type() == itVolume && item.IsOk() &&
m_objects_model->GetItemType(item) == itVolume &&
m_dragged_data.obj_idx() == m_objects_model->GetObjectIdByItem(item);
m_dragged_data.obj_idx() == m_objects_model->GetObjectIdByItem(item));
}
void ObjectList::OnDropPossible(wxDataViewEvent &event)
@ -1331,7 +1331,7 @@ void ObjectList::append_menu_items_add_volume(wxMenu* menu)
return;
}
for (int type = mode == comExpert ? 0 : 1 ; type < ADD_VOLUME_MENU_ITEMS.size(); type++)
for (size_t type = (mode == comExpert ? 0 : 1) ; type < ADD_VOLUME_MENU_ITEMS.size(); type++)
{
auto& item = ADD_VOLUME_MENU_ITEMS[type];
@ -1402,7 +1402,7 @@ wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_)
// Create new items for settings popupmenu
if (printer_technology() == ptFFF ||
menu->GetMenuItems().size() > 0 && !menu->GetMenuItems().back()->IsSeparator())
(menu->GetMenuItems().size() > 0 && !menu->GetMenuItems().back()->IsSeparator()))
menu->SetFirstSeparator();
// Add frequently settings
@ -1435,9 +1435,9 @@ wxMenuItem* ObjectList::append_menu_item_instance_to_object(wxMenu* menu, wxWind
[this](wxCommandEvent&) { split_instances(); }, "", menu, [](){return wxGetApp().plater()->can_set_instance_to_object(); }, parent);
}
wxMenuItem* ObjectList::append_menu_item_printable(wxMenu* menu, wxWindow* parent)
wxMenuItem* ObjectList::append_menu_item_printable(wxMenu* menu, wxWindow* /*parent*/)
{
return append_menu_check_item(menu, wxID_ANY, _(L("Printable")), "", [this](wxCommandEvent&) {
return append_menu_check_item(menu, wxID_ANY, _(L("Printable")), "", [](wxCommandEvent&) {
wxGetApp().plater()->canvas3D()->get_selection().toggle_instance_printable_state();
}, menu);
}
@ -1510,7 +1510,7 @@ void ObjectList::append_menu_item_delete(wxMenu* menu)
void ObjectList::append_menu_item_scale_selection_to_fit_print_volume(wxMenu* menu)
{
append_menu_item(menu, wxID_ANY, _(L("Scale to print volume")), _(L("Scale the selected object to fit the print volume")),
[this](wxCommandEvent&) { wxGetApp().plater()->scale_selection_to_fit_print_volume(); }, "", menu);
[](wxCommandEvent&) { wxGetApp().plater()->scale_selection_to_fit_print_volume(); }, "", menu);
}
void ObjectList::create_object_popupmenu(wxMenu *menu)
@ -1576,7 +1576,7 @@ void ObjectList::create_instance_popupmenu(wxMenu*menu)
* 2. Separate selected instances from the initial object to the separated object,
* if some (not all) instances are selected
*/
wxGetApp().plater()->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) {
wxGetApp().plater()->Bind(wxEVT_UPDATE_UI, [](wxUpdateUIEvent& evt) {
// evt.Enable(can_split_instances()); }, m_menu_item_split_instances->GetId());
evt.SetText(wxGetApp().plater()->canvas3D()->get_selection().is_single_full_object() ?
_(L("Set as a Separated Objects")) : _(L("Set as a Separated Object")));
@ -1588,7 +1588,7 @@ wxMenu* ObjectList::create_settings_popupmenu(wxMenu *parent_menu)
wxMenu *menu = new wxMenu;
settings_menu_hierarchy settings_menu;
const bool is_part = m_objects_model->GetParent(GetSelection()) != wxDataViewItem(0);
const bool is_part = m_objects_model->GetParent(GetSelection()) != wxDataViewItem(nullptr);
get_options_menu(settings_menu, is_part);
for (auto cat : settings_menu) {
@ -1681,7 +1681,7 @@ void ObjectList::load_part( ModelObject* model_object,
wxArrayString input_files;
wxGetApp().import_model(parent, input_files);
for (int i = 0; i < input_files.size(); ++i) {
for (size_t i = 0; i < input_files.size(); ++i) {
std::string input_file = input_files.Item(i).ToUTF8().data();
Model model;
@ -1719,7 +1719,7 @@ void ObjectList::load_part( ModelObject* model_object,
void ObjectList::load_generic_subobject(const std::string& type_name, const ModelVolumeType type)
{
const auto obj_idx = get_selected_obj_idx();
const int obj_idx = get_selected_obj_idx();
if (obj_idx < 0)
return;
@ -1852,9 +1852,9 @@ void ObjectList::del_settings_from_config(const wxDataViewItem& parent_item)
{
const bool is_layer_settings = m_objects_model->GetItemType(parent_item) == itLayer;
const int opt_cnt = m_config->keys().size();
if (opt_cnt == 1 && m_config->has("extruder") ||
is_layer_settings && opt_cnt == 2 && m_config->has("extruder") && m_config->has("layer_height"))
const size_t opt_cnt = m_config->keys().size();
if ((opt_cnt == 1 && m_config->has("extruder")) ||
(is_layer_settings && opt_cnt == 2 && m_config->has("extruder") && m_config->has("layer_height")))
return;
take_snapshot(_(L("Delete Settings")));
@ -2052,13 +2052,13 @@ wxDataViewItem ObjectList::add_layer_root_item(const wxDataViewItem obj_item)
if (obj_idx < 0 ||
object(obj_idx)->layer_config_ranges.empty() ||
printer_technology() == ptSLA)
return wxDataViewItem(0);
return wxDataViewItem(nullptr);
// create LayerRoot item
wxDataViewItem layers_item = m_objects_model->AddLayersRoot(obj_item);
// and create Layer item(s) according to the layer_config_ranges
for (const auto range : object(obj_idx)->layer_config_ranges)
for (const auto& range : object(obj_idx)->layer_config_ranges)
add_layer_item(range.first, layers_item);
Expand(layers_item);
@ -2150,7 +2150,7 @@ void ObjectList::part_selection_changed()
const auto item = GetSelection();
if ( multiple_selection() || item && m_objects_model->GetItemType(item) == itInstanceRoot )
if ( multiple_selection() || (item && m_objects_model->GetItemType(item) == itInstanceRoot ))
{
og_name = _(L("Group manipulation"));
@ -2162,7 +2162,7 @@ void ObjectList::part_selection_changed()
{
if (item)
{
if (m_objects_model->GetParent(item) == wxDataViewItem(0)) {
if (m_objects_model->GetParent(item) == wxDataViewItem(nullptr)) {
obj_idx = m_objects_model->GetIdByItem(item);
og_name = _(L("Object manipulation"));
m_config = &(*m_objects)[obj_idx]->config;
@ -2281,7 +2281,7 @@ SettingsBundle ObjectList::get_item_settings_bundle(const DynamicPrintConfig* co
// Add new SettingsItem for parent_item if it doesn't exist, or just update a digest according to new config
wxDataViewItem ObjectList::add_settings_item(wxDataViewItem parent_item, const DynamicPrintConfig* config)
{
wxDataViewItem ret = wxDataViewItem(0);
wxDataViewItem ret = wxDataViewItem(nullptr);
if (!parent_item)
return ret;
@ -2337,7 +2337,7 @@ void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed)
if (model_object->instances.size()>1)
{
std::vector<bool> print_idicator(model_object->instances.size());
for (int i = 0; i < model_object->instances.size(); ++i)
for (size_t i = 0; i < model_object->instances.size(); ++i)
print_idicator[i] = model_object->instances[i]->printable;
const wxDataViewItem object_item = m_objects_model->GetItemById(obj_idx);
@ -2364,7 +2364,7 @@ void ObjectList::delete_object_from_list()
auto item = GetSelection();
if (!item)
return;
if (m_objects_model->GetParent(item) == wxDataViewItem(0))
if (m_objects_model->GetParent(item) == wxDataViewItem(nullptr))
select_item(m_objects_model->Delete(item));
else
select_item(m_objects_model->Delete(m_objects_model->GetParent(item)));
@ -2521,7 +2521,7 @@ void ObjectList::remove()
wxDataViewItemArray sels;
GetSelections(sels);
wxDataViewItem parent = wxDataViewItem(0);
wxDataViewItem parent = wxDataViewItem(nullptr);
if (sels.Count() == 1)
parent = delete_item(GetSelection());
@ -2588,7 +2588,7 @@ void ObjectList::add_layer_range_after_current(const t_layer_height_range& curre
{
take_snapshot(_(L("Add Height Range")));
const t_layer_height_range& new_range = { last_range.second, last_range.second + 2.0f };
const t_layer_height_range& new_range = { last_range.second, last_range.second + 2. };
ranges[new_range] = get_default_layer_config(obj_idx);
add_layer_item(new_range, layers_item);
}
@ -2611,7 +2611,7 @@ void ObjectList::add_layer_range_after_current(const t_layer_height_range& curre
if (delta < get_min_layer_height(old_config.opt_int("extruder"))/*0.05f*/) // next range division has no sense
return;
const coordf_t midl_layer = next_range.first + 0.5f * delta;
const coordf_t midl_layer = next_range.first + 0.5 * delta;
t_layer_height_range new_range = { midl_layer, next_range.second };
@ -2711,7 +2711,7 @@ bool ObjectList::edit_layer_range(const t_layer_height_range& range, const t_lay
if (root_item.IsOk())
// create Layer item(s) according to the layer_config_ranges
for (const auto r : ranges)
for (const auto& r : ranges)
add_layer_item(r.first, root_item);
select_item(sel_type&itLayer ? m_objects_model->GetItemByLayerRange(obj_idx, new_range) : root_item);
@ -3028,7 +3028,7 @@ void ObjectList::select_item_all_children()
// There is no selection before OR some object is selected => select all objects
if (!GetSelection() || m_objects_model->GetItemType(GetSelection()) == itObject) {
for (int i = 0; i < m_objects->size(); i++)
for (size_t i = 0; i < m_objects->size(); i++)
sels.Add(m_objects_model->GetItemById(i));
m_selection_mode = smInstance;
}
@ -3054,7 +3054,7 @@ void ObjectList::update_selection_mode()
// All items are unselected
if (!GetSelection())
{
m_last_selected_item = wxDataViewItem(0);
m_last_selected_item = wxDataViewItem(nullptr);
m_selection_mode = smUndef;
return;
}
@ -3096,9 +3096,9 @@ bool ObjectList::check_last_selection(wxString& msg_str)
if (impossible_multi_selection(itVolume, smVolume) ||
impossible_multi_selection(itLayer, smLayer ) ||
type & itSettings ||
type & itVolume && !(m_selection_mode & smVolume ) ||
type & itLayer && !(m_selection_mode & smLayer ) ||
type & itInstance && !(m_selection_mode & smInstance)
(type & itVolume && !(m_selection_mode & smVolume )) ||
(type & itLayer && !(m_selection_mode & smLayer )) ||
(type & itInstance && !(m_selection_mode & smInstance))
)
{
// Inform user why selection isn't complited
@ -3151,7 +3151,7 @@ void ObjectList::fix_multiselection_conflicts()
const ItemType item_type = m_selection_mode & smVolume ? itVolume : itLayer;
for (const auto child : children)
for (const auto& child : children)
if (IsSelected(child) && m_objects_model->GetItemType(child) & item_type)
sels.Add(child);
@ -3161,7 +3161,7 @@ void ObjectList::fix_multiselection_conflicts()
}
else
{
for (const auto item : sels)
for (const auto& item : sels)
{
if (!IsSelected(item)) // if this item is unselected now (from previous actions)
continue;
@ -3172,13 +3172,13 @@ void ObjectList::fix_multiselection_conflicts()
}
const wxDataViewItem& parent = m_objects_model->GetParent(item);
if (parent != wxDataViewItem(0) && IsSelected(parent))
if (parent != wxDataViewItem(nullptr) && IsSelected(parent))
Unselect(parent);
else
{
wxDataViewItemArray unsels;
m_objects_model->GetAllChildren(item, unsels);
for (const auto unsel_item : unsels)
for (const auto& unsel_item : unsels)
Unselect(unsel_item);
}
@ -3193,7 +3193,7 @@ void ObjectList::fix_multiselection_conflicts()
show_info(this, msg_string, _(L("Info")));
if (!IsSelected(m_last_selected_item))
m_last_selected_item = wxDataViewItem(0);
m_last_selected_item = wxDataViewItem(nullptr);
m_prevent_list_events = false;
}
@ -3334,7 +3334,7 @@ void ObjectList::update_object_list_by_printer_technology()
GetSelections(sel); // stash selection
wxDataViewItemArray object_items;
m_objects_model->GetChildren(wxDataViewItem(0), object_items);
m_objects_model->GetChildren(wxDataViewItem(nullptr), object_items);
for (auto& object_item : object_items) {
// Update Settings Item for object
@ -3405,7 +3405,7 @@ void ObjectList::instances_to_separated_object(const int obj_idx, const std::set
// create new object from selected instance
ModelObject* model_object = (*m_objects)[obj_idx]->get_model()->add_object(*(*m_objects)[obj_idx]);
for (int inst_idx = model_object->instances.size() - 1; inst_idx >= 0; inst_idx--)
for (int inst_idx = int(model_object->instances.size()) - 1; inst_idx >= 0; inst_idx--)
{
if (find(inst_idxs.begin(), inst_idxs.end(), inst_idx) != inst_idxs.end())
continue;
@ -3599,7 +3599,7 @@ void ObjectList::OnEditingStarted(wxDataViewEvent &event)
{
m_last_selected_column = -1;
}
#endif __WXMSW__
#endif //__WXMSW__
void ObjectList::OnEditingDone(wxDataViewEvent &event)
{
@ -3618,7 +3618,7 @@ void ObjectList::OnEditingDone(wxDataViewEvent &event)
// Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected.
// Here the last active column is forgotten, so when leaving the editing mode, the next mouse click will not enter the editing mode of the newly selected column.
m_last_selected_column = -1;
#endif __WXMSW__
#endif //__WXMSW__
}
void ObjectList::show_multi_selection_menu()

View File

@ -116,7 +116,7 @@ bool ObjectSettings::update_settings_list()
auto optgroup = std::make_shared<ConfigOptionsGroup>(m_og->ctrl_parent(), _(cat.first), config, false, extra_column);
optgroup->label_width = 15;
optgroup->sidetext_width = 5.5;
optgroup->sidetext_width = 5;
optgroup->m_on_change = [this, config](const t_config_option_key& opt_id, const boost::any& value) {
this->update_config_values(config);
@ -241,4 +241,4 @@ void ObjectSettings::msw_rescale()
}
} //namespace GUI
} //namespace Slic3r
} //namespace Slic3r

View File

@ -5,11 +5,11 @@
#include <vector>
#include <wx/panel.h>
#include "wxExtensions.hpp"
#include "libslic3r/PrintConfig.hpp"
class wxBoxSizer;
namespace Slic3r {
class DynamicPrintConfig;
namespace GUI {
class ConfigOptionsGroup;

View File

@ -640,9 +640,10 @@ void Preview::update_double_slider(const std::vector<double>& layers_z, bool kee
bool snap_to_min = force_sliders_full_range || m_slider->is_lower_at_min();
bool snap_to_max = force_sliders_full_range || m_slider->is_higher_at_max();
std::vector<std::pair<int, double>> values;
fill_slider_values(values, layers_z);
m_slider->SetSliderValues(values);
std::vector<double> &ticks_from_config = (wxGetApp().preset_bundle->project_config.option<ConfigOptionFloats>("colorprint_heights"))->values;
check_slider_values(ticks_from_config, layers_z);
m_slider->SetSliderValues(layers_z);
assert(m_slider->GetMinValue() == 0);
m_slider->SetMaxValue(layers_z.empty() ? 0 : layers_z.size() - 1);
@ -662,9 +663,6 @@ void Preview::update_double_slider(const std::vector<double>& layers_z, bool kee
}
m_slider->SetSelectionSpan(idx_low, idx_high);
const auto& config = wxGetApp().preset_bundle->project_config;
const std::vector<double> &ticks_from_config = (config.option<ConfigOptionFloats>("colorprint_heights"))->values;
m_slider->SetTicksValues(ticks_from_config);
bool color_print_enable = (wxGetApp().plater()->printer_technology() == ptFFF);
@ -676,26 +674,18 @@ void Preview::update_double_slider(const std::vector<double>& layers_z, bool kee
m_slider->EnableTickManipulation(color_print_enable);
}
void Preview::fill_slider_values(std::vector<std::pair<int, double>> &values,
void Preview::check_slider_values(std::vector<double>& ticks_from_config,
const std::vector<double> &layers_z)
{
values.clear();
for (int i = 0; i < layers_z.size(); ++i)
{
values.push_back(std::pair<int, double>(i + 1, layers_z[i]));
}
// All ticks that would end up outside the slider range should be erased.
// TODO: this should be placed into more appropriate part of code,
// this function is e.g. not called when the last object is deleted
std::vector<double> &ticks_from_config = (wxGetApp().preset_bundle->project_config.option<ConfigOptionFloats>("colorprint_heights"))->values;
unsigned int old_size = ticks_from_config.size();
ticks_from_config.erase(std::remove_if(ticks_from_config.begin(), ticks_from_config.end(),
[values](double val)
[layers_z](double val)
{
return (values.back().second < val &&
// we can't ignore tick on last layer
fabs(values.back().second - val) > DoubleSlider::epsilon());
auto it = std::lower_bound(layers_z.begin(), layers_z.end(), val - DoubleSlider::epsilon());
return it == layers_z.end();
}),
ticks_from_config.end());
if (ticks_from_config.size() != old_size)

View File

@ -155,7 +155,7 @@ private:
// Create/Update/Reset double slider on 3dPreview
void create_double_slider();
void update_double_slider(const std::vector<double>& layers_z, bool keep_z_range = false);
void fill_slider_values(std::vector<std::pair<int, double>> &values,
void check_slider_values(std::vector<double> &ticks_from_config,
const std::vector<double> &layers_z);
void reset_double_slider();
// update DoubleSlider after keyDown in canvas

View File

@ -69,7 +69,6 @@ public:
enum EState
{
Off,
Hover,
On,
Num_States
};

View File

@ -44,12 +44,12 @@ public:
Vec3d get_flattening_normal() const;
protected:
virtual bool on_init();
virtual std::string on_get_name() const;
virtual bool on_is_activable() const;
virtual void on_start_dragging();
virtual void on_render() const;
virtual void on_render_for_picking() const;
virtual bool on_init() override;
virtual std::string on_get_name() const override;
virtual bool on_is_activable() const override;
virtual void on_start_dragging() override;
virtual void on_render() const override;
virtual void on_render_for_picking() const override;
virtual void on_set_state() override;
};

View File

@ -87,16 +87,12 @@ protected:
virtual void on_set_state()
{
for (GLGizmoRotate& g : m_gizmos)
{
g.set_state(m_state);
}
}
virtual void on_set_hover_id()
{
for (int i = 0; i < 3; ++i)
{
m_gizmos[i].set_hover_id((m_hover_id == i) ? 0 : -1);
}
}
virtual void on_enable_grabber(unsigned int id)
{

View File

@ -329,6 +329,7 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
case X: { local_offset_vec = local_offset * Vec3d::UnitX(); break; }
case Y: { local_offset_vec = local_offset * Vec3d::UnitY(); break; }
case Z: { local_offset_vec = local_offset * Vec3d::UnitZ(); break; }
default: break;
}
m_offset = m_offsets_transform * local_offset_vec;

View File

@ -12,7 +12,9 @@
#include "slic3r/GUI/GUI.hpp"
#include "slic3r/GUI/GUI_ObjectSettings.hpp"
#include "slic3r/GUI/GUI_ObjectList.hpp"
#include "slic3r/GUI/Plater.hpp"
#include "slic3r/GUI/PresetBundle.hpp"
#include "libslic3r/SLAPrint.hpp"
#include "libslic3r/Tesselate.hpp"
@ -306,7 +308,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
}
else {
render_color[3] = 1.f;
if ((m_hover_id == i && m_editing_mode)) { // ignore hover state unless editing mode is active
if ((size_t(m_hover_id) == i && m_editing_mode)) { // ignore hover state unless editing mode is active
render_color[0] = 0.f;
render_color[1] = 1.0f;
render_color[2] = 1.0f;
@ -328,7 +330,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
// Inverse matrix of the instance scaling is applied so that the mark does not scale with the object.
glsafe(::glPushMatrix());
glsafe(::glTranslated(support_point.pos(0), support_point.pos(1), support_point.pos(2)));
glsafe(::glTranslatef(support_point.pos(0), support_point.pos(1), support_point.pos(2)));
glsafe(::glMultMatrixd(instance_scaling_matrix_inverse.data()));
if (vol->is_left_handed())
@ -345,16 +347,16 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
Eigen::AngleAxisd aa(q);
glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2)));
const float cone_radius = 0.25f; // mm
const float cone_height = 0.75f;
const double cone_radius = 0.25; // mm
const double cone_height = 0.75;
glsafe(::glPushMatrix());
glsafe(::glTranslatef(0.f, 0.f, support_point.head_front_radius * RenderPointScale));
::gluCylinder(m_quadric, 0.f, cone_radius, cone_height, 24, 1);
::gluCylinder(m_quadric, 0., cone_radius, cone_height, 24, 1);
glsafe(::glTranslatef(0.f, 0.f, cone_height));
::gluDisk(m_quadric, 0.0, cone_radius, 24, 1);
glsafe(::glPopMatrix());
}
::gluSphere(m_quadric, support_point.head_front_radius * RenderPointScale, 24, 12);
::gluSphere(m_quadric, (double)support_point.head_front_radius * RenderPointScale, 24, 12);
if (vol->is_left_handed())
glFrontFace(GL_CCW);
@ -775,7 +777,7 @@ std::vector<const ConfigOption*> GLGizmoSlaSupports::get_config_options(const st
}
void GLGizmoSlaSupports::update_cache_entry_normal(unsigned int i) const
void GLGizmoSlaSupports::update_cache_entry_normal(size_t i) const
{
int idx = 0;
Eigen::Matrix<float, 1, 3> pp = m_editing_cache[i].support_point.pos;
@ -1098,9 +1100,6 @@ std::string GLGizmoSlaSupports::on_get_name() const
void GLGizmoSlaSupports::on_set_state()
{
if (m_state == Hover)
return;
// m_model_object pointer can be invalid (for instance because of undo/redo action),
// we should recover it from the object id
m_model_object = nullptr;
@ -1111,6 +1110,9 @@ void GLGizmoSlaSupports::on_set_state()
}
}
if (m_state == m_old_state)
return;
if (m_state == On && m_old_state != On) { // the gizmo was just turned on
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on")));
if (is_mesh_update_necessary())

View File

@ -11,7 +11,6 @@
#include "slic3r/GUI/I18N.hpp" // ...and redefine again when we are done with the igl code
#include "libslic3r/SLA/SLACommon.hpp"
#include "libslic3r/SLAPrint.hpp"
#include <wx/dialog.h>
#include <cereal/types/vector.hpp>
@ -31,7 +30,7 @@ private:
ObjectID m_model_object_id = 0;
int m_active_instance = -1;
float m_active_instance_bb_radius; // to cache the bb
mutable float m_z_shift = 0.f;
mutable double m_z_shift = 0.f;
bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal);
const float RenderPointScale = 1.f;
@ -78,7 +77,7 @@ private:
public:
GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
virtual ~GLGizmoSlaSupports();
~GLGizmoSlaSupports() override;
void set_sla_support_data(ModelObject* model_object, const Selection& selection);
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
void delete_selected_points(bool force = false);
@ -90,21 +89,19 @@ public:
void reslice_SLA_supports(bool postpone_error_messages = false) const;
private:
bool on_init();
void on_update(const UpdateData& data);
virtual void on_render() const;
virtual void on_render_for_picking() const;
bool on_init() override;
void on_update(const UpdateData& data) override;
void on_render() const override;
void on_render_for_picking() const override;
//void render_selection_rectangle() const;
void render_points(const Selection& selection, bool picking = false) const;
void render_clipping_plane(const Selection& selection) const;
bool is_mesh_update_necessary() const;
void update_mesh();
void update_cache_entry_normal(unsigned int i) const;
void update_cache_entry_normal(size_t i) const;
bool unsaved_changes() const;
EState m_no_hover_state = Off;
EState m_no_hover_old_state = Off;
bool m_lock_unique_islands = false;
bool m_editing_mode = false; // Is editing mode active?
bool m_old_editing_state = false; // To keep track of whether the user toggled between the modes (needed for imgui refreshes).
@ -157,20 +154,21 @@ private:
protected:
void on_set_state() override;
virtual void on_set_hover_id()
void on_set_hover_id() override
{
if (! m_editing_mode || (int)m_editing_cache.size() <= m_hover_id)
m_hover_id = -1;
}
void on_start_dragging() override;
void on_stop_dragging() override;
virtual void on_render_input_window(float x, float y, float bottom_limit) override;
void on_render_input_window(float x, float y, float bottom_limit) override;
virtual std::string on_get_name() const;
virtual bool on_is_activable() const;
virtual bool on_is_selectable() const;
virtual void on_load(cereal::BinaryInputArchive& ar) override;
virtual void on_save(cereal::BinaryOutputArchive& ar) const override;
std::string on_get_name() const override;
bool on_is_activable() const override;
bool on_is_selectable() const override;
void on_load(cereal::BinaryInputArchive& ar) override;
void on_save(cereal::BinaryOutputArchive& ar) const override;
};

View File

@ -29,9 +29,49 @@ GLGizmosManager::GLGizmosManager(GLCanvas3D& parent)
{
}
GLGizmosManager::~GLGizmosManager()
std::vector<size_t> GLGizmosManager::get_selectable_idxs() const
{
reset();
std::vector<size_t> out;
for (size_t i=0; i<m_gizmos.size(); ++i)
if (m_gizmos[i]->is_selectable())
out.push_back(i);
return out;
}
std::vector<size_t> GLGizmosManager::get_activable_idxs() const
{
std::vector<size_t> out;
for (size_t i=0; i<m_gizmos.size(); ++i)
if (m_gizmos[i]->is_activable())
out.push_back(i);
return out;
}
size_t GLGizmosManager::get_gizmo_idx_from_mouse(const Vec2d& mouse_pos) const
{
if (! m_enabled)
return Undefined;
float cnv_h = (float)m_parent.get_canvas_size().get_height();
float height = get_total_overlay_height();
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
float scaled_border = m_overlay_border * m_overlay_scale;
float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
float top_y = 0.5f * (cnv_h - height) + scaled_border;
// is mouse horizontally in the area?
if ((scaled_border <= (float)mouse_pos(0) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size))) {
// which icon is it on?
size_t from_top = (size_t)((float)mouse_pos(1) - top_y)/scaled_stride_y;
// is it really on the icon or already past the border?
if ((float)mouse_pos(1) <= top_y + from_top*scaled_stride_y + scaled_icons_size) {
std::vector<size_t> selectable = get_selectable_idxs();
if (from_top < selectable.size())
return selectable[from_top];
}
}
return Undefined;
}
bool GLGizmosManager::init()
@ -45,77 +85,25 @@ bool GLGizmosManager::init()
if (!m_background_texture.metadata.filename.empty())
{
if (!m_background_texture.texture.load_from_file(resources_dir() + "/icons/" + m_background_texture.metadata.filename, false, GLTexture::SingleThreaded, false))
{
reset();
return false;
}
m_gizmos.emplace_back(new GLGizmoMove3D(m_parent, "move.svg", 0));
m_gizmos.emplace_back(new GLGizmoScale3D(m_parent, "scale.svg", 1));
m_gizmos.emplace_back(new GLGizmoRotate3D(m_parent, "rotate.svg", 2));
m_gizmos.emplace_back(new GLGizmoFlatten(m_parent, "place.svg", 3));
m_gizmos.emplace_back(new GLGizmoCut(m_parent, "cut.svg", 4));
m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 5));
for (auto& gizmo : m_gizmos) {
if (! gizmo->init()) {
m_gizmos.clear();
return false;
}
}
GLGizmoBase* gizmo = new GLGizmoMove3D(m_parent, "move.svg", 0);
if (gizmo == nullptr)
return false;
if (!gizmo->init())
return false;
m_gizmos.insert(GizmosMap::value_type(Move, gizmo));
gizmo = new GLGizmoScale3D(m_parent, "scale.svg", 1);
if (gizmo == nullptr)
return false;
if (!gizmo->init())
return false;
m_gizmos.insert(GizmosMap::value_type(Scale, gizmo));
gizmo = new GLGizmoRotate3D(m_parent, "rotate.svg", 2);
if (gizmo == nullptr)
{
reset();
return false;
}
if (!gizmo->init())
{
reset();
return false;
}
m_gizmos.insert(GizmosMap::value_type(Rotate, gizmo));
gizmo = new GLGizmoFlatten(m_parent, "place.svg", 3);
if (gizmo == nullptr)
return false;
if (!gizmo->init()) {
reset();
return false;
}
m_gizmos.insert(GizmosMap::value_type(Flatten, gizmo));
gizmo = new GLGizmoCut(m_parent, "cut.svg", 4);
if (gizmo == nullptr)
return false;
if (!gizmo->init()) {
reset();
return false;
}
m_gizmos.insert(GizmosMap::value_type(Cut, gizmo));
gizmo = new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 5);
if (gizmo == nullptr)
return false;
if (!gizmo->init()) {
reset();
return false;
}
m_gizmos.insert(GizmosMap::value_type(SlaSupports, gizmo));
m_current = Undefined;
m_hover = Undefined;
return true;
}
@ -140,65 +128,39 @@ void GLGizmosManager::set_overlay_scale(float scale)
void GLGizmosManager::refresh_on_off_state()
{
if (m_serializing)
if (m_serializing || m_current == Undefined || m_gizmos.empty())
return;
GizmosMap::iterator it = m_gizmos.find(m_current);
if ((it != m_gizmos.end()) && (it->second != nullptr))
{
if (!it->second->is_activable())
{
it->second->set_state(GLGizmoBase::Off);
m_current = Undefined;
}
}
if (m_current != Undefined && ! m_gizmos[m_current]->is_activable())
activate_gizmo(Undefined);
}
void GLGizmosManager::reset_all_states()
{
if (!m_enabled)
if (! m_enabled || m_serializing)
return;
if (m_serializing)
return;
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
{
if (it->second != nullptr)
{
it->second->set_state(GLGizmoBase::Off);
it->second->set_hover_id(-1);
}
}
m_current = Undefined;
activate_gizmo(Undefined);
m_hover = Undefined;
}
void GLGizmosManager::set_hover_id(int id)
{
if (!m_enabled)
if (!m_enabled || m_current == Undefined)
return;
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
{
if ((it->second != nullptr) && (it->second->get_state() == GLGizmoBase::On))
it->second->set_hover_id(id);
}
m_gizmos[m_current]->set_hover_id(id);
}
void GLGizmosManager::enable_grabber(EType type, unsigned int id, bool enable)
{
if (!m_enabled)
if (!m_enabled || type == Undefined || m_gizmos.empty())
return;
GizmosMap::const_iterator it = m_gizmos.find(type);
if (it != m_gizmos.end())
{
if (enable)
it->second->enable_grabber(id);
else
it->second->disable_grabber(id);
}
if (enable)
m_gizmos[type]->enable_grabber(id);
else
m_gizmos[type]->disable_grabber(id);
}
void GLGizmosManager::update(const Linef3& mouse_ray, const Point& mouse_pos)
@ -269,8 +231,9 @@ bool GLGizmosManager::is_running() const
if (!m_enabled)
return false;
GLGizmoBase* curr = get_current();
return (curr != nullptr) ? (curr->get_state() == GLGizmoBase::On) : false;
//GLGizmoBase* curr = get_current();
//return (curr != nullptr) ? (curr->get_state() == GLGizmoBase::On) : false;
return m_current != Undefined;
}
bool GLGizmosManager::handle_shortcut(int key)
@ -283,43 +246,12 @@ bool GLGizmosManager::handle_shortcut(int key)
bool handled = false;
for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
{
if ((it->second == nullptr) || !it->second->is_selectable())
continue;
for (size_t idx : get_selectable_idxs()) {
int it_key = m_gizmos[idx]->get_shortcut_key();
int it_key = it->second->get_shortcut_key();
if (it->second->is_activable() && ((it_key == key - 64) || (it_key == key - 96)))
{
if ((it->second->get_state() == GLGizmoBase::On))
{
it->second->set_state(GLGizmoBase::Off);
if (it->second->get_state() == GLGizmoBase::Off) {
m_current = Undefined;
}
if (m_gizmos[idx]->is_activable() && ((it_key == key - 64) || (it_key == key - 96))) {
activate_gizmo(m_current == idx ? Undefined : (EType)idx);
handled = true;
}
else if ((it->second->get_state() == GLGizmoBase::Off))
{
// Before turning anything on, turn everything else off to see if
// nobody refuses. Only then activate the gizmo.
bool can_open = true;
for (GizmosMap::iterator i = m_gizmos.begin(); i != m_gizmos.end(); ++i) {
if (i->first != it->first) {
if (m_current == i->first && i->second->get_state() != GLGizmoBase::Off ) {
i->second->set_state(GLGizmoBase::Off);
if (i->second->get_state() != GLGizmoBase::Off)
can_open = false;
}
}
}
if (can_open) {
it->second->set_state(GLGizmoBase::On);
m_current = it->first;
}
handled = true;
}
}
}
@ -328,31 +260,25 @@ bool GLGizmosManager::handle_shortcut(int key)
bool GLGizmosManager::is_dragging() const
{
if (!m_enabled)
if (! m_enabled || m_current == Undefined)
return false;
GLGizmoBase* curr = get_current();
return (curr != nullptr) ? curr->is_dragging() : false;
return m_gizmos[m_current]->is_dragging();
}
void GLGizmosManager::start_dragging()
{
if (!m_enabled)
if (! m_enabled || m_current == Undefined)
return;
GLGizmoBase* curr = get_current();
if (curr != nullptr)
curr->start_dragging();
m_gizmos[m_current]->start_dragging();
}
void GLGizmosManager::stop_dragging()
{
if (!m_enabled)
if (! m_enabled || m_current == Undefined)
return;
GLGizmoBase* curr = get_current();
if (curr != nullptr)
curr->stop_dragging();
m_gizmos[m_current]->stop_dragging();
}
Vec3d GLGizmosManager::get_displacement() const
@ -360,8 +286,7 @@ Vec3d GLGizmosManager::get_displacement() const
if (!m_enabled)
return Vec3d::Zero();
GizmosMap::const_iterator it = m_gizmos.find(Move);
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoMove3D*>(it->second)->get_displacement() : Vec3d::Zero();
return dynamic_cast<GLGizmoMove3D*>(m_gizmos[Move].get())->get_displacement();
}
Vec3d GLGizmosManager::get_scale() const
@ -369,126 +294,101 @@ Vec3d GLGizmosManager::get_scale() const
if (!m_enabled)
return Vec3d::Ones();
GizmosMap::const_iterator it = m_gizmos.find(Scale);
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoScale3D*>(it->second)->get_scale() : Vec3d::Ones();
return dynamic_cast<GLGizmoScale3D*>(m_gizmos[Scale].get())->get_scale();
}
void GLGizmosManager::set_scale(const Vec3d& scale)
{
if (!m_enabled)
if (!m_enabled || m_gizmos.empty())
return;
GizmosMap::const_iterator it = m_gizmos.find(Scale);
if (it != m_gizmos.end())
reinterpret_cast<GLGizmoScale3D*>(it->second)->set_scale(scale);
dynamic_cast<GLGizmoScale3D*>(m_gizmos[Scale].get())->set_scale(scale);
}
Vec3d GLGizmosManager::get_scale_offset() const
{
if (!m_enabled)
if (!m_enabled || m_gizmos.empty())
return Vec3d::Zero();
GizmosMap::const_iterator it = m_gizmos.find(Scale);
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoScale3D*>(it->second)->get_offset() : Vec3d::Zero();
return dynamic_cast<GLGizmoScale3D*>(m_gizmos[Scale].get())->get_offset();
}
Vec3d GLGizmosManager::get_rotation() const
{
if (!m_enabled)
if (!m_enabled || m_gizmos.empty())
return Vec3d::Zero();
GizmosMap::const_iterator it = m_gizmos.find(Rotate);
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoRotate3D*>(it->second)->get_rotation() : Vec3d::Zero();
return dynamic_cast<GLGizmoRotate3D*>(m_gizmos[Rotate].get())->get_rotation();
}
void GLGizmosManager::set_rotation(const Vec3d& rotation)
{
if (!m_enabled)
if (!m_enabled || m_gizmos.empty())
return;
GizmosMap::const_iterator it = m_gizmos.find(Rotate);
if (it != m_gizmos.end())
reinterpret_cast<GLGizmoRotate3D*>(it->second)->set_rotation(rotation);
dynamic_cast<GLGizmoRotate3D*>(m_gizmos[Rotate].get())->set_rotation(rotation);
}
Vec3d GLGizmosManager::get_flattening_normal() const
{
if (!m_enabled)
if (!m_enabled || m_gizmos.empty())
return Vec3d::Zero();
GizmosMap::const_iterator it = m_gizmos.find(Flatten);
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoFlatten*>(it->second)->get_flattening_normal() : Vec3d::Zero();
return dynamic_cast<GLGizmoFlatten*>(m_gizmos[Flatten].get())->get_flattening_normal();
}
void GLGizmosManager::set_flattening_data(const ModelObject* model_object)
{
if (!m_enabled)
if (!m_enabled || m_gizmos.empty())
return;
GizmosMap::const_iterator it = m_gizmos.find(Flatten);
if (it != m_gizmos.end())
reinterpret_cast<GLGizmoFlatten*>(it->second)->set_flattening_data(model_object);
dynamic_cast<GLGizmoFlatten*>(m_gizmos[Flatten].get())->set_flattening_data(model_object);
}
void GLGizmosManager::set_sla_support_data(ModelObject* model_object)
{
if (!m_enabled)
if (!m_enabled || m_gizmos.empty())
return;
GizmosMap::const_iterator it = m_gizmos.find(SlaSupports);
if (it != m_gizmos.end())
reinterpret_cast<GLGizmoSlaSupports*>(it->second)->set_sla_support_data(model_object, m_parent.get_selection());
dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get())->set_sla_support_data(model_object, m_parent.get_selection());
}
// Returns true if the gizmo used the event to do something, false otherwise.
bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down)
{
if (!m_enabled)
if (!m_enabled || m_gizmos.empty())
return false;
GizmosMap::const_iterator it = m_gizmos.find(SlaSupports);
if (it != m_gizmos.end())
return reinterpret_cast<GLGizmoSlaSupports*>(it->second)->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
return false;
return dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
}
ClippingPlane GLGizmosManager::get_sla_clipping_plane() const
{
if (!m_enabled || m_current != SlaSupports)
if (!m_enabled || m_current != SlaSupports || m_gizmos.empty())
return ClippingPlane::ClipsNothing();
GizmosMap::const_iterator it = m_gizmos.find(SlaSupports);
if (it != m_gizmos.end())
return reinterpret_cast<GLGizmoSlaSupports*>(it->second)->get_sla_clipping_plane();
return ClippingPlane::ClipsNothing();
return dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get())->get_sla_clipping_plane();
}
bool GLGizmosManager::wants_reslice_supports_on_undo() const
{
return (m_current == SlaSupports
&& dynamic_cast<const GLGizmoSlaSupports*>(m_gizmos.at(SlaSupports))->has_backend_supports());
&& dynamic_cast<const GLGizmoSlaSupports*>(m_gizmos.at(SlaSupports).get())->has_backend_supports());
}
void GLGizmosManager::render_current_gizmo() const
{
if (!m_enabled)
if (!m_enabled || m_current == Undefined)
return;
GLGizmoBase* curr = get_current();
if (curr != nullptr)
curr->render();
m_gizmos[m_current]->render();
}
void GLGizmosManager::render_current_gizmo_for_picking_pass() const
{
if (!m_enabled)
if (! m_enabled || m_current == Undefined)
return;
GLGizmoBase* curr = get_current();
if (curr != nullptr)
curr->render_for_picking();
m_gizmos[m_current]->render_for_picking();
}
void GLGizmosManager::render_overlay() const
@ -547,7 +447,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
// if the button down was done on this toolbar, prevent from dragging into the scene
processed = true;
if (!overlay_contains_mouse(mouse_pos))
if (get_gizmo_idx_from_mouse(mouse_pos) == Undefined)
{
// mouse is outside the toolbar
m_tooltip = "";
@ -557,14 +457,12 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
if ((m_current == SlaSupports) && gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown()))
// the gizmo got the event and took some action, there is no need to do anything more
processed = true;
else if (!selection.is_empty() && grabber_contains_mouse())
{
else if (!selection.is_empty() && grabber_contains_mouse()) {
update_data();
selection.start_dragging();
start_dragging();
if (m_current == Flatten)
{
if (m_current == Flatten) {
// Rotate the object so the normal points downward:
m_parent.do_flatten(get_flattening_normal(), L("Gizmo-Place on Face"));
wxGetApp().obj_manipul()->set_dirty();
@ -634,25 +532,14 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
}
else if (evt.LeftUp() && is_dragging())
{
switch (m_current)
{
case Move:
{
m_parent.do_move(L("Gizmo-Move"));
break;
}
case Scale:
{
m_parent.do_scale(L("Gizmo-Scale"));
break;
}
case Rotate:
{
m_parent.do_rotate(L("Gizmo-Rotate"));
break;
}
default:
break;
switch (m_current) {
case Move : m_parent.do_move(L("Gizmo-Move"));
break;
case Scale : m_parent.do_scale(L("Gizmo-Scale"));
break;
case Rotate : m_parent.do_rotate(L("Gizmo-Rotate"));
break;
default : break;
}
stop_dragging();
@ -842,7 +729,7 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt)
{
if (m_current == SlaSupports)
{
GLGizmoSlaSupports* gizmo = reinterpret_cast<GLGizmoSlaSupports*>(get_current());
GLGizmoSlaSupports* gizmo = dynamic_cast<GLGizmoSlaSupports*>(get_current());
if (keyCode == WXK_SHIFT)
{
@ -863,7 +750,8 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt)
}
else if (evt.GetEventType() == wxEVT_KEY_DOWN)
{
if ((m_current == SlaSupports) && ((keyCode == WXK_SHIFT) || (keyCode == WXK_ALT)) && reinterpret_cast<GLGizmoSlaSupports*>(get_current())->is_in_editing_mode())
if ((m_current == SlaSupports) && ((keyCode == WXK_SHIFT) || (keyCode == WXK_ALT))
&& dynamic_cast<GLGizmoSlaSupports*>(get_current())->is_in_editing_mode())
{
// m_parent.set_cursor(GLCanvas3D::Cross);
processed = true;
@ -882,18 +770,7 @@ void GLGizmosManager::update_after_undo_redo(const UndoRedo::Snapshot& snapshot)
m_serializing = false;
if (m_current == SlaSupports
&& snapshot.snapshot_data.flags & UndoRedo::SnapshotData::RECALCULATE_SLA_SUPPORTS)
dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports])->reslice_SLA_supports(true);
}
void GLGizmosManager::reset()
{
for (GizmosMap::value_type& gizmo : m_gizmos)
{
delete gizmo.second;
gizmo.second = nullptr;
}
m_gizmos.clear();
dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get())->reslice_SLA_supports(true);
}
void GLGizmosManager::render_background(float left, float top, float right, float bottom, float border) const
@ -911,7 +788,7 @@ void GLGizmosManager::render_background(float left, float top, float right, floa
float internal_top = top - border;
float internal_bottom = bottom + border;
float left_uv = 0.0f;
// float left_uv = 0.0f;
float right_uv = 1.0f;
float top_uv = 1.0f;
float bottom_uv = 0.0f;
@ -981,33 +858,32 @@ void GLGizmosManager::do_render_overlay() const
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale * inv_zoom;
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
unsigned int icons_texture_id = m_icons_texture.get_id();
unsigned int tex_width = m_icons_texture.get_width();
unsigned int tex_height = m_icons_texture.get_height();
float inv_tex_width = (tex_width != 0) ? 1.0f / (float)tex_width : 0.0f;
float inv_tex_height = (tex_height != 0) ? 1.0f / (float)tex_height : 0.0f;
int tex_width = m_icons_texture.get_width();
int tex_height = m_icons_texture.get_height();
float inv_tex_width = (tex_width != 0) ? 1.0f / tex_width : 0.0f;
float inv_tex_height = (tex_height != 0) ? 1.0f / tex_height : 0.0f;
if ((icons_texture_id == 0) || (tex_width <= 0) || (tex_height <= 0))
return;
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
for (size_t idx : get_selectable_idxs())
{
if ((it->second == nullptr) || !it->second->is_selectable())
continue;
GLGizmoBase* gizmo = m_gizmos[idx].get();
unsigned int sprite_id = it->second->get_sprite_id();
GLGizmoBase::EState state = it->second->get_state();
unsigned int sprite_id = gizmo->get_sprite_id();
int icon_idx = m_current == idx ? 2 : (m_hover == idx ? 1 : 0);
float u_icon_size = m_overlay_icons_size * m_overlay_scale * inv_tex_width;
float v_icon_size = m_overlay_icons_size * m_overlay_scale * inv_tex_height;
float v_top = sprite_id * v_icon_size;
float u_left = state * u_icon_size;
float u_left = icon_idx * u_icon_size;
float v_bottom = v_top + v_icon_size;
float u_right = u_left + u_icon_size;
GLTexture::render_sub_texture(icons_texture_id, top_x, top_x + scaled_icons_size, top_y - scaled_icons_size, top_y, { { u_left, v_bottom }, { u_right, v_bottom }, { u_right, v_top }, { u_left, v_top } });
if (it->second->get_state() == GLGizmoBase::On) {
float toolbar_top = (float)cnv_h - m_parent.get_view_toolbar_height();
it->second->render_input_window(width, 0.5f * cnv_h - top_y * zoom, toolbar_top);
if (idx == m_current) {
float toolbar_top = cnv_h - m_parent.get_view_toolbar_height();
gizmo->render_input_window(width, 0.5f * cnv_h - top_y * zoom, toolbar_top);
}
top_y -= scaled_stride_y;
}
@ -1021,13 +897,14 @@ float GLGizmosManager::get_total_overlay_height() const
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
float height = 2.0f * scaled_border;
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
/*for (size_t idx=0; idx<m_gizmos.size(); ++idx)
{
if ((it->second == nullptr) || !it->second->is_selectable())
if ((m_gizmos[idx] == nullptr) || !m_gizmos[idx]->is_selectable())
continue;
height += scaled_stride_y;
}
}*/
height += get_selectable_idxs().size() * scaled_stride_y;
return height - scaled_gap_y;
}
@ -1039,19 +916,21 @@ float GLGizmosManager::get_total_overlay_width() const
GLGizmoBase* GLGizmosManager::get_current() const
{
GizmosMap::const_iterator it = m_gizmos.find(m_current);
return (it != m_gizmos.end()) ? it->second : nullptr;
if (m_current==Undefined || m_gizmos.empty())
return nullptr;
else
return m_gizmos[m_current].get();
}
bool GLGizmosManager::generate_icons_texture() const
{
std::string path = resources_dir() + "/icons/";
std::vector<std::string> filenames;
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
for (size_t idx=0; idx<m_gizmos.size(); ++idx)
{
if (it->second != nullptr)
if (m_gizmos[idx] != nullptr)
{
const std::string& icon_filename = it->second->get_icon_filename();
const std::string& icon_filename = m_gizmos[idx]->get_icon_filename();
if (!icon_filename.empty())
filenames.push_back(path + icon_filename);
}
@ -1074,74 +953,9 @@ void GLGizmosManager::update_on_off_state(const Vec2d& mouse_pos)
if (!m_enabled)
return;
float cnv_h = (float)m_parent.get_canvas_size().get_height();
float height = get_total_overlay_height();
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
float scaled_border = m_overlay_border * m_overlay_scale;
float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
float top_y = 0.5f * (cnv_h - height) + scaled_border;
auto inside = [scaled_border, scaled_icons_size, &mouse_pos](float top_y) {
return (scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size);
};
bool could_activate = true;
for (std::pair<const GLGizmosManager::EType, GLGizmoBase*> &type_and_gizmo : m_gizmos)
{
GLGizmoBase *gizmo = type_and_gizmo.second;
if ((gizmo == nullptr) || !gizmo->is_selectable())
continue;
if (! (gizmo->is_activable() && inside(top_y))) {
gizmo->set_state(GLGizmoBase::Off);
if (gizmo->get_state() != GLGizmoBase::Off) {
// Gizmo refused to leave it's active state. Don't try to select
could_activate = false;
}
}
top_y += scaled_stride_y;
}
// We may change m_current soon. If we did it during following loop, gizmos that take undo/redo snapshots
// in their on_set_state function could snapshot a state with the new gizmo already active.
// Therefore, just remember what needs to be done and actually change m_current afterwards.
EType new_current = m_current;
top_y = 0.5f * (cnv_h - height) + scaled_border;
for (std::pair<const GLGizmosManager::EType, GLGizmoBase*> &type_and_gizmo : m_gizmos)
{
GLGizmoBase *gizmo = type_and_gizmo.second;
if ((gizmo == nullptr) || !gizmo->is_selectable())
continue;
if (gizmo->is_activable() && inside(top_y))
{
if ((gizmo->get_state() == GLGizmoBase::On))
{
gizmo->set_state(GLGizmoBase::Off);
if (gizmo->get_state() == GLGizmoBase::Off) {
gizmo->set_state(GLGizmoBase::Hover);
new_current = Undefined;
}
}
else if ((gizmo->get_state() == GLGizmoBase::Hover) && could_activate)
{
gizmo->set_state(GLGizmoBase::On);
new_current = type_and_gizmo.first;
}
}
top_y += scaled_stride_y;
}
m_current = new_current;
if (could_activate) {
GizmosMap::iterator it = m_gizmos.find(m_current);
if ((it != m_gizmos.end()) && (it->second != nullptr) && (it->second->get_state() != GLGizmoBase::On))
it->second->set_state(GLGizmoBase::On);
}
size_t idx = get_gizmo_idx_from_mouse(mouse_pos);
if (idx != Undefined && m_gizmos[idx]->is_activable() && m_hover == idx)
activate_gizmo(m_current == idx ? Undefined : (EType)idx);
}
std::string GLGizmosManager::update_hover_state(const Vec2d& mouse_pos)
@ -1151,60 +965,37 @@ std::string GLGizmosManager::update_hover_state(const Vec2d& mouse_pos)
if (!m_enabled)
return name;
float cnv_h = (float)m_parent.get_canvas_size().get_height();
float height = get_total_overlay_height();
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
float scaled_border = m_overlay_border * m_overlay_scale;
float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
float top_y = 0.5f * (cnv_h - height) + scaled_border;
m_hover = Undefined;
for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
{
if ((it->second == nullptr) || !it->second->is_selectable())
continue;
size_t idx = get_gizmo_idx_from_mouse(mouse_pos);
if (idx != Undefined) {
name = m_gizmos[idx]->get_name();
bool inside = (scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size);
if (inside)
name = it->second->get_name();
if (it->second->is_activable() && (it->second->get_state() != GLGizmoBase::On))
it->second->set_state(inside ? GLGizmoBase::Hover : GLGizmoBase::Off);
top_y += scaled_stride_y;
if (m_gizmos[idx]->is_activable())
m_hover = (EType)idx;
}
return name;
}
bool GLGizmosManager::overlay_contains_mouse(const Vec2d& mouse_pos) const
void GLGizmosManager::activate_gizmo(EType type)
{
if (!m_enabled)
return false;
if (m_gizmos.empty() || m_current == type)
return;
float cnv_h = (float)m_parent.get_canvas_size().get_height();
float height = get_total_overlay_height();
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
float scaled_border = m_overlay_border * m_overlay_scale;
float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
float top_y = 0.5f * (cnv_h - height) + scaled_border;
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
{
if ((it->second == nullptr) || !it->second->is_selectable())
continue;
if ((scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size))
return true;
top_y += scaled_stride_y;
if (m_current != Undefined) {
m_gizmos[m_current]->set_state(GLGizmoBase::Off);
if (m_gizmos[m_current]->get_state() != GLGizmoBase::Off)
return; // gizmo refused to be turned off, do nothing.
}
return false;
if (type != Undefined)
m_gizmos[type]->set_state(GLGizmoBase::On);
m_current = type;
}
bool GLGizmosManager::grabber_contains_mouse() const
{
if (!m_enabled)

View File

@ -54,25 +54,30 @@ public:
enum EType : unsigned char
{
Undefined,
Move,
Scale,
Rotate,
Flatten,
Cut,
SlaSupports,
Num_Types
Undefined
};
private:
GLCanvas3D& m_parent;
bool m_enabled;
typedef std::map<EType, GLGizmoBase*> GizmosMap;
GizmosMap m_gizmos;
std::vector<std::unique_ptr<GLGizmoBase>> m_gizmos;
mutable GLTexture m_icons_texture;
mutable bool m_icons_texture_dirty;
BackgroundTexture m_background_texture;
EType m_current;
EType m_hover;
std::vector<size_t> get_selectable_idxs() const;
std::vector<size_t> get_activable_idxs() const;
size_t get_gizmo_idx_from_mouse(const Vec2d& mouse_pos) const;
void activate_gizmo(EType type);
float m_overlay_icons_size;
float m_overlay_scale;
@ -98,7 +103,6 @@ private:
public:
explicit GLGizmosManager(GLCanvas3D& parent);
~GLGizmosManager();
bool init();
@ -112,16 +116,8 @@ public:
ar(m_current);
GLGizmoBase* curr = get_current();
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it) {
GLGizmoBase* gizmo = it->second;
if (gizmo != nullptr) {
gizmo->set_hover_id(-1);
gizmo->set_state((it->second == curr) ? GLGizmoBase::On : GLGizmoBase::Off);
if (gizmo == curr)
gizmo->load(ar);
}
}
if (m_current != Undefined)
m_gizmos[m_current]->load(ar);
}
template<class Archive>
@ -132,9 +128,8 @@ public:
ar(m_current);
GLGizmoBase* curr = get_current();
if (curr != nullptr)
curr->save(ar);
if (m_current != Undefined && !m_gizmos.empty())
m_gizmos[m_current]->save(ar);
}
bool is_enabled() const { return m_enabled; }
@ -195,8 +190,6 @@ public:
void update_after_undo_redo(const UndoRedo::Snapshot& snapshot);
private:
void reset();
void render_background(float left, float top, float right, float bottom, float border) const;
void do_render_overlay() const;
@ -209,7 +202,6 @@ private:
void update_on_off_state(const Vec2d& mouse_pos);
std::string update_hover_state(const Vec2d& mouse_pos);
bool overlay_contains_mouse(const Vec2d& mouse_pos) const;
bool grabber_contains_mouse() const;
};

View File

@ -50,8 +50,9 @@ class MainFrame : public DPIFrame
wxString m_qs_last_input_file = wxEmptyString;
wxString m_qs_last_output_file = wxEmptyString;
wxString m_last_config = wxEmptyString;
wxMenuItem* m_menu_item_repeat { nullptr };
#if 0
wxMenuItem* m_menu_item_repeat { nullptr }; // doesn't used now
#endif
wxMenuItem* m_menu_item_reslice_now { nullptr };
PrintHostQueueDialog *m_printhost_queue_dlg;

View File

@ -457,8 +457,9 @@ void ConfigOptionsGroup::Show(const bool show)
bool ConfigOptionsGroup::update_visibility(ConfigOptionMode mode) {
if (m_options_mode.empty())
return true;
if (m_grid_sizer->GetEffectiveRowsCount() != m_options_mode.size() &&
m_options_mode.size() == 1)
int opt_mode_size = m_options_mode.size();
if (m_grid_sizer->GetEffectiveRowsCount() != opt_mode_size &&
opt_mode_size == 1)
return m_options_mode[0] <= mode;
Show(true);
@ -476,7 +477,7 @@ bool ConfigOptionsGroup::update_visibility(ConfigOptionMode mode) {
coef+= cols;
}
if (hidden_row_cnt == m_options_mode.size()) {
if (hidden_row_cnt == opt_mode_size) {
sizer->ShowItems(false);
return false;
}

View File

@ -510,24 +510,27 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) :
option.opt.sidetext = "";
line.append_option(option);
auto wiping_dialog_btn = [config, this](wxWindow* parent) {
auto wiping_dialog_btn = [this](wxWindow* parent) {
m_wiping_dialog_button = new wxButton(parent, wxID_ANY, _(L("Purging volumes")) + dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
m_wiping_dialog_button->SetFont(wxGetApp().normal_font());
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(m_wiping_dialog_button, 0, wxALIGN_CENTER_VERTICAL);
m_wiping_dialog_button->Bind(wxEVT_BUTTON, ([parent](wxCommandEvent& e)
{
auto &config = wxGetApp().preset_bundle->project_config;
const std::vector<double> &init_matrix = (config.option<ConfigOptionFloats>("wiping_volumes_matrix"))->values;
const std::vector<double> &init_extruders = (config.option<ConfigOptionFloats>("wiping_volumes_extruders"))->values;
auto &project_config = wxGetApp().preset_bundle->project_config;
const std::vector<double> &init_matrix = (project_config.option<ConfigOptionFloats>("wiping_volumes_matrix"))->values;
const std::vector<double> &init_extruders = (project_config.option<ConfigOptionFloats>("wiping_volumes_extruders"))->values;
WipingDialog dlg(parent, cast<float>(init_matrix), cast<float>(init_extruders));
const DynamicPrintConfig* config = &wxGetApp().preset_bundle->printers.get_edited_preset().config;
const std::vector<std::string> &extruder_colours = (config->option<ConfigOptionStrings>("extruder_colour"))->values;
WipingDialog dlg(parent, cast<float>(init_matrix), cast<float>(init_extruders), extruder_colours);
if (dlg.ShowModal() == wxID_OK) {
std::vector<float> matrix = dlg.get_matrix();
std::vector<float> extruders = dlg.get_extruders();
(config.option<ConfigOptionFloats>("wiping_volumes_matrix"))->values = std::vector<double>(matrix.begin(), matrix.end());
(config.option<ConfigOptionFloats>("wiping_volumes_extruders"))->values = std::vector<double>(extruders.begin(), extruders.end());
(project_config.option<ConfigOptionFloats>("wiping_volumes_matrix"))->values = std::vector<double>(matrix.begin(), matrix.end());
(project_config.option<ConfigOptionFloats>("wiping_volumes_extruders"))->values = std::vector<double>(extruders.begin(), extruders.end());
wxPostEvent(parent, SimpleEvent(EVT_SCHEDULE_BACKGROUND_PROCESS, parent));
}
}));
@ -1072,8 +1075,6 @@ void Sidebar::show_info_sizer()
return;
}
const ModelInstance* model_instance = !model_object->instances.empty() ? model_object->instances.front() : nullptr;
auto size = model_object->bounding_box().size();
p->object_info->info_size->SetLabel(wxString::Format("%.2f x %.2f x %.2f",size(0), size(1), size(2)));
p->object_info->info_materials->SetLabel(wxString::Format("%d", static_cast<int>(model_object->materials_count())));
@ -2284,20 +2285,20 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
if (! is_project_file) {
if (model.looks_like_multipart_object()) {
wxMessageDialog dlg(q, _(L(
wxMessageDialog msg_dlg(q, _(L(
"This file contains several objects positioned at multiple heights. "
"Instead of considering them as multiple objects, should I consider\n"
"this file as a single object having multiple parts?\n"
)), _(L("Multi-part object detected")), wxICON_WARNING | wxYES | wxNO);
if (dlg.ShowModal() == wxID_YES) {
if (msg_dlg.ShowModal() == wxID_YES) {
model.convert_multipart_object(nozzle_dmrs->values.size());
}
}
}
else if ((wxGetApp().get_mode() == comSimple) && (type_3mf || type_any_amf) && model_has_advanced_features(model)) {
wxMessageDialog dlg(q, _(L("This file cannot be loaded in a simple mode. Do you want to switch to an advanced mode?\n")),
wxMessageDialog msg_dlg(q, _(L("This file cannot be loaded in a simple mode. Do you want to switch to an advanced mode?\n")),
_(L("Detected advanced data")), wxICON_WARNING | wxYES | wxNO);
if (dlg.ShowModal() == wxID_YES)
if (msg_dlg.ShowModal() == wxID_YES)
{
Slic3r::GUI::wxGetApp().save_mode(comAdvanced);
view3D->set_as_dirty();
@ -2336,12 +2337,12 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
}
if (new_model != nullptr && new_model->objects.size() > 1) {
wxMessageDialog dlg(q, _(L(
wxMessageDialog msg_dlg(q, _(L(
"Multiple objects were loaded for a multi-material printer.\n"
"Instead of considering them as multiple objects, should I consider\n"
"these files to represent a single object having multiple parts?\n"
)), _(L("Multi-part object detected")), wxICON_WARNING | wxYES | wxNO);
if (dlg.ShowModal() == wxID_YES) {
if (msg_dlg.ShowModal() == wxID_YES) {
new_model->convert_multipart_object(nozzle_dmrs->values.size());
}
@ -3260,6 +3261,7 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
else
this->update_sla_scene();
break;
default: break;
}
} else if (evt.status.flags & PrintBase::SlicingStatus::RELOAD_SLA_PREVIEW) {
// Update the SLA preview. Only called if not RELOAD_SLA_SUPPORT_POINTS, as the block above will refresh the preview anyways.
@ -3279,6 +3281,7 @@ void Plater::priv::on_slicing_completed(wxCommandEvent &)
else
this->update_sla_scene();
break;
default: break;
}
}
@ -3325,6 +3328,7 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt)
else
this->update_sla_scene();
break;
default: break;
}
if (canceled) {

View File

@ -697,6 +697,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
config.option<ConfigOptionString>("default_sla_print_profile", true);
config.option<ConfigOptionString>("default_sla_material_profile", true);
break;
default: break;
}
// 1) Create a name from the file name.
@ -805,6 +806,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
load_preset(this->sla_materials, 1, "sla_material_settings_id");
load_preset(this->printers, 2, "printer_settings_id");
break;
default: break;
}
this->update_compatible(false);
@ -1349,6 +1351,7 @@ void PresetBundle::update_compatible(bool select_other_if_incompatible)
[&prefered_sla_material_profile](const std::string& profile_name){ return profile_name == prefered_sla_material_profile; });
break;
}
default: break;
}
}

View File

@ -89,7 +89,7 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle
double bridge_flow_ratio = print_config.opt_float("bridge_flow_ratio");
double perimeter_speed = print_config.opt_float("perimeter_speed");
double external_perimeter_speed = print_config.get_abs_value("external_perimeter_speed", perimeter_speed);
double gap_fill_speed = print_config.opt_float("gap_fill_speed");
// double gap_fill_speed = print_config.opt_float("gap_fill_speed");
double infill_speed = print_config.opt_float("infill_speed");
double small_perimeter_speed = print_config.get_abs_value("small_perimeter_speed", perimeter_speed);
double solid_infill_speed = print_config.get_abs_value("solid_infill_speed", infill_speed);
@ -123,7 +123,7 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle
// Current filament values
double filament_diameter = filament_config.opt_float("filament_diameter", 0);
double filament_crossection = M_PI * 0.25 * filament_diameter * filament_diameter;
double extrusion_multiplier = filament_config.opt_float("extrusion_multiplier", 0);
// double extrusion_multiplier = filament_config.opt_float("extrusion_multiplier", 0);
// The following value will be annotated by this hint, so it does not take part in the calculation.
// double filament_max_volumetric_speed = filament_config.opt_float("filament_max_volumetric_speed", 0);

View File

@ -310,7 +310,7 @@ void Selection::remove_volume(unsigned int object_idx, unsigned int volume_idx)
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
{
GLVolume* v = (*m_volumes)[i];
if ((v->object_idx() == object_idx) && (v->volume_idx() == volume_idx))
if ((v->object_idx() == (int)object_idx) && (v->volume_idx() == (int)volume_idx))
do_remove_volume(i);
}
@ -992,7 +992,7 @@ void Selection::translate(unsigned int object_idx, const Vec3d& displacement)
for (unsigned int i : m_list)
{
GLVolume* v = (*m_volumes)[i];
if (v->object_idx() == object_idx)
if (v->object_idx() == (int)object_idx)
v->set_instance_offset(v->get_instance_offset() + displacement);
}
@ -1037,7 +1037,7 @@ void Selection::translate(unsigned int object_idx, unsigned int instance_idx, co
for (unsigned int i : m_list)
{
GLVolume* v = (*m_volumes)[i];
if ((v->object_idx() == object_idx) && (v->instance_idx() == instance_idx))
if ((v->object_idx() == (int)object_idx) && (v->instance_idx() == (int)instance_idx))
v->set_instance_offset(v->get_instance_offset() + displacement);
}
@ -1063,7 +1063,7 @@ void Selection::translate(unsigned int object_idx, unsigned int instance_idx, co
continue;
GLVolume* v = (*m_volumes)[j];
if ((v->object_idx() != object_idx) || (v->instance_idx() != instance_idx))
if ((v->object_idx() != object_idx) || (v->instance_idx() != (int)instance_idx))
continue;
v->set_instance_offset(v->get_instance_offset() + displacement);
@ -1154,7 +1154,7 @@ void Selection::erase()
for (const ItemForDelete& i : items_set) {
if (i.type == ItemType::itVolume) {
const int vol_in_obj_cnt = volumes_in_obj.find(i.obj_idx) == volumes_in_obj.end() ? 0 : volumes_in_obj.at(i.obj_idx);
if (vol_in_obj_cnt == m_model->objects[i.obj_idx]->volumes.size()) {
if (vol_in_obj_cnt == (int)m_model->objects[i.obj_idx]->volumes.size()) {
if (i.sub_obj_idx == vol_in_obj_cnt - 1)
items.emplace_back(ItemType::itObject, i.obj_idx, 0);
continue;
@ -1389,7 +1389,7 @@ std::vector<unsigned int> Selection::get_volume_idxs_from_object(unsigned int ob
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
{
if ((*m_volumes)[i]->object_idx() == object_idx)
if ((*m_volumes)[i]->object_idx() == (int)object_idx)
idxs.push_back(i);
}
@ -1403,7 +1403,7 @@ std::vector<unsigned int> Selection::get_volume_idxs_from_instance(unsigned int
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
{
const GLVolume* v = (*m_volumes)[i];
if ((v->object_idx() == object_idx) && (v->instance_idx() == instance_idx))
if ((v->object_idx() == (int)object_idx) && (v->instance_idx() == (int)instance_idx))
idxs.push_back(i);
}
@ -1417,9 +1417,9 @@ std::vector<unsigned int> Selection::get_volume_idxs_from_volume(unsigned int ob
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
{
const GLVolume* v = (*m_volumes)[i];
if ((v->object_idx() == object_idx) && (v->volume_idx() == volume_idx))
if ((v->object_idx() == (int)object_idx) && (v->volume_idx() == (int)volume_idx))
{
if ((instance_idx != -1) && (v->instance_idx() == instance_idx))
if (((int)instance_idx != -1) && (v->instance_idx() == (int)instance_idx))
idxs.push_back(i);
}
}
@ -1607,7 +1607,7 @@ void Selection::update_type()
}
else
{
int sels_cntr = 0;
unsigned int sels_cntr = 0;
for (ObjectIdxsToInstanceIdxsMap::iterator it = m_cache.content.begin(); it != m_cache.content.end(); ++it)
{
const ModelObject* model_object = m_model->objects[it->first];
@ -1759,7 +1759,7 @@ void Selection::do_remove_instance(unsigned int object_idx, unsigned int instanc
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
{
GLVolume* v = (*m_volumes)[i];
if ((v->object_idx() == object_idx) && (v->instance_idx() == instance_idx))
if ((v->object_idx() == (int)object_idx) && (v->instance_idx() == (int)instance_idx))
do_remove_volume(i);
}
}
@ -1769,7 +1769,7 @@ void Selection::do_remove_object(unsigned int object_idx)
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
{
GLVolume* v = (*m_volumes)[i];
if (v->object_idx() == object_idx)
if (v->object_idx() == (int)object_idx)
do_remove_volume(i);
}
}
@ -1836,7 +1836,6 @@ void Selection::render_synchronized_volumes() const
{
const GLVolume* volume = (*m_volumes)[i];
int object_idx = volume->object_idx();
int instance_idx = volume->instance_idx();
int volume_idx = volume->volume_idx();
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j)
{

View File

@ -995,6 +995,7 @@ void Tab::update_preset_description_line()
description_line += "\n\n\t" + _(L("default SLA print profile")) + ": \n\t\t" + default_sla_print_profile;
break;
}
default: break;
}
}
}
@ -1263,251 +1264,9 @@ void TabPrint::update()
if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA)
return; // ys_FIXME
/*
// #ys_FIXME_to_delete
//! Temporary workaround for the correct updates of the TextCtrl (like "layer_height"):
// KillFocus() for the wxSpinCtrl use CallAfter function. So,
// to except the duplicate call of the update() after dialog->ShowModal(),
// let check if this process is already started.
if (is_msg_dlg_already_exist)
return;
*/
m_update_cnt++;
// Freeze();
/* #ys_FIXME_delete_after_testing (refactoring)
*
// layer_height shouldn't be equal to zero
if (m_config->opt_float("layer_height") < EPSILON)
{
const wxString msg_text = _(L("Zero layer height is not valid.\n\nThe layer height will be reset to 0.01."));
wxMessageDialog dialog(parent(), msg_text, _(L("Layer height")), wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *m_config;
is_msg_dlg_already_exist = true;
dialog.ShowModal();
new_conf.set_key_value("layer_height", new ConfigOptionFloat(0.01));
load_config(new_conf);
is_msg_dlg_already_exist = false;
}
if (fabs(m_config->option<ConfigOptionFloatOrPercent>("first_layer_height")->value - 0) < EPSILON)
{
const wxString msg_text = _(L("Zero first layer height is not valid.\n\nThe first layer height will be reset to 0.01."));
wxMessageDialog dialog(parent(), msg_text, _(L("First layer height")), wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *m_config;
is_msg_dlg_already_exist = true;
dialog.ShowModal();
new_conf.set_key_value("first_layer_height", new ConfigOptionFloatOrPercent(0.01, false));
load_config(new_conf);
is_msg_dlg_already_exist = false;
}
double fill_density = m_config->option<ConfigOptionPercent>("fill_density")->value;
if (m_config->opt_bool("spiral_vase") &&
!(m_config->opt_int("perimeters") == 1 && m_config->opt_int("top_solid_layers") == 0 &&
fill_density == 0)) {
wxString msg_text = _(L("The Spiral Vase mode requires:\n"
"- one perimeter\n"
"- no top solid layers\n"
"- 0% fill density\n"
"- no support material\n"
"- no ensure_vertical_shell_thickness\n"
"\nShall I adjust those settings in order to enable Spiral Vase?"));
wxMessageDialog dialog(parent(), msg_text, _(L("Spiral Vase")), wxICON_WARNING | wxYES | wxNO);
DynamicPrintConfig new_conf = *m_config;
if (dialog.ShowModal() == wxID_YES) {
new_conf.set_key_value("perimeters", new ConfigOptionInt(1));
new_conf.set_key_value("top_solid_layers", new ConfigOptionInt(0));
new_conf.set_key_value("fill_density", new ConfigOptionPercent(0));
new_conf.set_key_value("support_material", new ConfigOptionBool(false));
new_conf.set_key_value("support_material_enforce_layers", new ConfigOptionInt(0));
new_conf.set_key_value("ensure_vertical_shell_thickness", new ConfigOptionBool(false));
fill_density = 0;
}
else {
new_conf.set_key_value("spiral_vase", new ConfigOptionBool(false));
}
load_config(new_conf);
on_value_change("fill_density", fill_density);
}
if (m_config->opt_bool("wipe_tower") && m_config->opt_bool("support_material") &&
m_config->opt_float("support_material_contact_distance") > 0. &&
(m_config->opt_int("support_material_extruder") != 0 || m_config->opt_int("support_material_interface_extruder") != 0)) {
wxString msg_text = _(L("The Wipe Tower currently supports the non-soluble supports only\n"
"if they are printed with the current extruder without triggering a tool change.\n"
"(both support_material_extruder and support_material_interface_extruder need to be set to 0).\n"
"\nShall I adjust those settings in order to enable the Wipe Tower?"));
wxMessageDialog dialog(parent(), msg_text, _(L("Wipe Tower")), wxICON_WARNING | wxYES | wxNO);
DynamicPrintConfig new_conf = *m_config;
if (dialog.ShowModal() == wxID_YES) {
new_conf.set_key_value("support_material_extruder", new ConfigOptionInt(0));
new_conf.set_key_value("support_material_interface_extruder", new ConfigOptionInt(0));
}
else
new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false));
load_config(new_conf);
}
if (m_config->opt_bool("wipe_tower") && m_config->opt_bool("support_material") &&
m_config->opt_float("support_material_contact_distance") == 0 &&
!m_config->opt_bool("support_material_synchronize_layers")) {
wxString msg_text = _(L("For the Wipe Tower to work with the soluble supports, the support layers\n"
"need to be synchronized with the object layers.\n"
"\nShall I synchronize support layers in order to enable the Wipe Tower?"));
wxMessageDialog dialog(parent(), msg_text, _(L("Wipe Tower")), wxICON_WARNING | wxYES | wxNO);
DynamicPrintConfig new_conf = *m_config;
if (dialog.ShowModal() == wxID_YES) {
new_conf.set_key_value("support_material_synchronize_layers", new ConfigOptionBool(true));
}
else
new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false));
load_config(new_conf);
}
if (m_config->opt_bool("support_material")) {
// Ask only once.
if (!m_support_material_overhangs_queried) {
m_support_material_overhangs_queried = true;
if (!m_config->opt_bool("overhangs")/* != 1* /) {
wxString msg_text = _(L("Supports work better, if the following feature is enabled:\n"
"- Detect bridging perimeters\n"
"\nShall I adjust those settings for supports?"));
wxMessageDialog dialog(parent(), msg_text, _(L("Support Generator")), wxICON_WARNING | wxYES | wxNO | wxCANCEL);
DynamicPrintConfig new_conf = *m_config;
auto answer = dialog.ShowModal();
if (answer == wxID_YES) {
// Enable "detect bridging perimeters".
new_conf.set_key_value("overhangs", new ConfigOptionBool(true));
} else if (answer == wxID_NO) {
// Do nothing, leave supports on and "detect bridging perimeters" off.
} else if (answer == wxID_CANCEL) {
// Disable supports.
new_conf.set_key_value("support_material", new ConfigOptionBool(false));
m_support_material_overhangs_queried = false;
}
load_config(new_conf);
}
}
}
else {
m_support_material_overhangs_queried = false;
}
if (m_config->option<ConfigOptionPercent>("fill_density")->value == 100) {
auto fill_pattern = m_config->option<ConfigOptionEnum<InfillPattern>>("fill_pattern")->value;
std::string str_fill_pattern = "";
t_config_enum_values map_names = m_config->option<ConfigOptionEnum<InfillPattern>>("fill_pattern")->get_enum_values();
for (auto it : map_names) {
if (fill_pattern == it.second) {
str_fill_pattern = it.first;
break;
}
}
if (!str_fill_pattern.empty()) {
const std::vector<std::string> &external_fill_pattern = m_config->def()->get("top_fill_pattern")->enum_values;
bool correct_100p_fill = false;
for (const std::string &fill : external_fill_pattern)
{
if (str_fill_pattern == fill)
correct_100p_fill = true;
}
// get fill_pattern name from enum_labels for using this one at dialog_msg
str_fill_pattern = _utf8(m_config->def()->get("fill_pattern")->enum_labels[fill_pattern]);
if (!correct_100p_fill) {
wxString msg_text = GUI::from_u8((boost::format(_utf8(L("The %1% infill pattern is not supposed to work at 100%% density.\n\n"
"Shall I switch to rectilinear fill pattern?"))) % str_fill_pattern).str());
wxMessageDialog dialog(parent(), msg_text, _(L("Infill")), wxICON_WARNING | wxYES | wxNO);
DynamicPrintConfig new_conf = *m_config;
if (dialog.ShowModal() == wxID_YES) {
new_conf.set_key_value("fill_pattern", new ConfigOptionEnum<InfillPattern>(ipRectilinear));
fill_density = 100;
}
else
fill_density = m_presets->get_selected_preset().config.option<ConfigOptionPercent>("fill_density")->value;
new_conf.set_key_value("fill_density", new ConfigOptionPercent(fill_density));
load_config(new_conf);
on_value_change("fill_density", fill_density);
}
}
}
bool have_perimeters = m_config->opt_int("perimeters") > 0;
for (auto el : {"extra_perimeters", "ensure_vertical_shell_thickness", "thin_walls", "overhangs",
"seam_position", "external_perimeters_first", "external_perimeter_extrusion_width",
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed" })
get_field(el)->toggle(have_perimeters);
bool have_infill = m_config->option<ConfigOptionPercent>("fill_density")->value > 0;
// infill_extruder uses the same logic as in Print::extruders()
for (auto el : {"fill_pattern", "infill_every_layers", "infill_only_where_needed",
"solid_infill_every_layers", "solid_infill_below_area", "infill_extruder" })
get_field(el)->toggle(have_infill);
bool have_solid_infill = m_config->opt_int("top_solid_layers") > 0 || m_config->opt_int("bottom_solid_layers") > 0;
// solid_infill_extruder uses the same logic as in Print::extruders()
for (auto el : {"top_fill_pattern", "bottom_fill_pattern", "infill_first", "solid_infill_extruder",
"solid_infill_extrusion_width", "solid_infill_speed" })
get_field(el)->toggle(have_solid_infill);
for (auto el : {"fill_angle", "bridge_angle", "infill_extrusion_width",
"infill_speed", "bridge_speed" })
get_field(el)->toggle(have_infill || have_solid_infill);
get_field("gap_fill_speed")->toggle(have_perimeters && have_infill);
bool have_top_solid_infill = m_config->opt_int("top_solid_layers") > 0;
for (auto el : { "top_infill_extrusion_width", "top_solid_infill_speed" })
get_field(el)->toggle(have_top_solid_infill);
bool have_default_acceleration = m_config->opt_float("default_acceleration") > 0;
for (auto el : {"perimeter_acceleration", "infill_acceleration",
"bridge_acceleration", "first_layer_acceleration" })
get_field(el)->toggle(have_default_acceleration);
bool have_skirt = m_config->opt_int("skirts") > 0 || m_config->opt_float("min_skirt_length") > 0;
for (auto el : { "skirt_distance", "skirt_height" })
get_field(el)->toggle(have_skirt);
bool have_brim = m_config->opt_float("brim_width") > 0;
// perimeter_extruder uses the same logic as in Print::extruders()
get_field("perimeter_extruder")->toggle(have_perimeters || have_brim);
bool have_raft = m_config->opt_int("raft_layers") > 0;
bool have_support_material = m_config->opt_bool("support_material") || have_raft;
bool have_support_material_auto = have_support_material && m_config->opt_bool("support_material_auto");
bool have_support_interface = m_config->opt_int("support_material_interface_layers") > 0;
bool have_support_soluble = have_support_material && m_config->opt_float("support_material_contact_distance") == 0;
for (auto el : {"support_material_pattern", "support_material_with_sheath",
"support_material_spacing", "support_material_angle", "support_material_interface_layers",
"dont_support_bridges", "support_material_extrusion_width", "support_material_contact_distance",
"support_material_xy_spacing" })
get_field(el)->toggle(have_support_material);
get_field("support_material_threshold")->toggle(have_support_material_auto);
for (auto el : {"support_material_interface_spacing", "support_material_interface_extruder",
"support_material_interface_speed", "support_material_interface_contact_loops" })
get_field(el)->toggle(have_support_material && have_support_interface);
get_field("support_material_synchronize_layers")->toggle(have_support_soluble);
get_field("perimeter_extrusion_width")->toggle(have_perimeters || have_skirt || have_brim);
get_field("support_material_extruder")->toggle(have_support_material || have_skirt);
get_field("support_material_speed")->toggle(have_support_material || have_brim || have_skirt);
bool have_sequential_printing = m_config->opt_bool("complete_objects");
for (auto el : { "extruder_clearance_radius", "extruder_clearance_height" })
get_field(el)->toggle(have_sequential_printing);
bool have_ooze_prevention = m_config->opt_bool("ooze_prevention");
get_field("standby_temperature_delta")->toggle(have_ooze_prevention);
bool have_wipe_tower = m_config->opt_bool("wipe_tower");
for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging"})
get_field(el)->toggle(have_wipe_tower);
*/
m_config_manipulation.update_print_fff_config(m_config, true);
m_recommended_thin_wall_thickness_description_line->SetText(
@ -3826,84 +3585,6 @@ void TabSLAPrint::update()
m_update_cnt++;
/* #ys_FIXME_delete_after_testing (refactoring)
*
bool supports_en = m_config->opt_bool("supports_enable");
get_field("support_head_front_diameter")->toggle(supports_en);
get_field("support_head_penetration")->toggle(supports_en);
get_field("support_head_width")->toggle(supports_en);
get_field("support_pillar_diameter")->toggle(supports_en);
get_field("support_pillar_connection_mode")->toggle(supports_en);
get_field("support_buildplate_only")->toggle(supports_en);
get_field("support_base_diameter")->toggle(supports_en);
get_field("support_base_height")->toggle(supports_en);
get_field("support_base_safety_distance")->toggle(supports_en);
get_field("support_critical_angle")->toggle(supports_en);
get_field("support_max_bridge_length")->toggle(supports_en);
get_field("support_max_pillar_link_distance")->toggle(supports_en);
get_field("support_points_density_relative")->toggle(supports_en);
get_field("support_points_minimal_distance")->toggle(supports_en);
bool pad_en = m_config->opt_bool("pad_enable");
get_field("pad_wall_thickness")->toggle(pad_en);
get_field("pad_wall_height")->toggle(pad_en);
get_field("pad_max_merge_distance")->toggle(pad_en);
// get_field("pad_edge_radius")->toggle(supports_en);
get_field("pad_wall_slope")->toggle(pad_en);
get_field("pad_around_object")->toggle(pad_en);
double head_penetration = m_config->opt_float("support_head_penetration");
double head_width = m_config->opt_float("support_head_width");
if (head_penetration > head_width) {
wxString msg_text = _(
L("Head penetration should not be greater than the head width."));
wxMessageDialog dialog(parent(),
msg_text,
_(L("Invalid Head penetration")),
wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *m_config;
if (dialog.ShowModal() == wxID_OK) {
new_conf.set_key_value("support_head_penetration",
new ConfigOptionFloat(head_width));
}
load_config(new_conf);
}
double pinhead_d = m_config->opt_float("support_head_front_diameter");
double pillar_d = m_config->opt_float("support_pillar_diameter");
if (pinhead_d > pillar_d) {
wxString msg_text = _(L(
"Pinhead diameter should be smaller than the pillar diameter."));
wxMessageDialog dialog (parent(),
msg_text,
_(L("Invalid pinhead diameter")),
wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *m_config;
if (dialog.ShowModal() == wxID_OK) {
new_conf.set_key_value("support_head_front_diameter",
new ConfigOptionFloat(pillar_d / 2.0));
}
load_config(new_conf);
}
bool has_suppad = pad_en && supports_en;
bool zero_elev = m_config->opt_bool("pad_around_object") && has_suppad;
get_field("support_object_elevation")->toggle(supports_en && !zero_elev);
get_field("pad_object_gap")->toggle(zero_elev);
get_field("pad_object_connector_stride")->toggle(zero_elev);
get_field("pad_object_connector_width")->toggle(zero_elev);
get_field("pad_object_connector_penetration")->toggle(zero_elev);
*/
m_config_manipulation.update_print_sla_config(m_config, true);
m_update_cnt--;

View File

@ -321,7 +321,6 @@ protected:
class TabPrint : public Tab
{
bool is_msg_dlg_already_exist {false};
public:
TabPrint(wxNotebook* parent) :
// Tab(parent, _(L("Print Settings")), L("print")) {}

View File

@ -1,6 +1,7 @@
#include <algorithm>
#include <sstream>
#include "WipeTowerDialog.hpp"
#include "PresetBundle.hpp"
#include "GUI.hpp"
#include "I18N.hpp"
#include "GUI_App.hpp"
@ -137,11 +138,11 @@ std::string RammingPanel::get_parameters()
// Parent dialog for purging volume adjustments - it fathers WipingPanel widget (that contains all controls) and a button to toggle simple/advanced mode:
WipingDialog::WipingDialog(wxWindow* parent,const std::vector<float>& matrix, const std::vector<float>& extruders)
WipingDialog::WipingDialog(wxWindow* parent, const std::vector<float>& matrix, const std::vector<float>& extruders, const std::vector<std::string>& extruder_colours)
: wxDialog(parent, wxID_ANY, _(L("Wipe tower - Purging volume adjustment")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE/* | wxRESIZE_BORDER*/)
{
auto widget_button = new wxButton(this,wxID_ANY,"-",wxPoint(0,0),wxDefaultSize);
m_panel_wiping = new WipingPanel(this,matrix,extruders, widget_button);
m_panel_wiping = new WipingPanel(this,matrix,extruders, extruder_colours, widget_button);
auto main_sizer = new wxBoxSizer(wxVERTICAL);
@ -180,7 +181,7 @@ void WipingPanel::format_sizer(wxSizer* sizer, wxPanel* page, wxGridSizer* grid_
}
// This panel contains all control widgets for both simple and advanced mode (these reside in separate sizers)
WipingPanel::WipingPanel(wxWindow* parent, const std::vector<float>& matrix, const std::vector<float>& extruders, wxButton* widget_button)
WipingPanel::WipingPanel(wxWindow* parent, const std::vector<float>& matrix, const std::vector<float>& extruders, const std::vector<std::string>& extruder_colours, wxButton* widget_button)
: wxPanel(parent,wxID_ANY, wxDefaultPosition, wxDefaultSize/*,wxBORDER_RAISED*/)
{
m_widget_button = widget_button; // pointer to the button in parent dialog
@ -188,6 +189,12 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector<float>& matrix, con
m_number_of_extruders = (int)(sqrt(matrix.size())+0.001);
for (const std::string& color : extruder_colours) {
unsigned char rgb[3];
Slic3r::PresetBundle::parse_color(color, rgb);
m_colours.push_back(wxColor(rgb[0], rgb[1], rgb[2]));
}
// Create two switched panels with their own sizers
m_sizer_simple = new wxBoxSizer(wxVERTICAL);
m_sizer_advanced = new wxBoxSizer(wxVERTICAL);
@ -211,14 +218,36 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector<float>& matrix, con
edit_boxes[i][j]->SetValue(wxString("") << int(matrix[m_number_of_extruders*j + i]));
}
}
const int clr_icon_side = edit_boxes.front().front()->GetSize().y;
const auto icon_size = wxSize(clr_icon_side, clr_icon_side);
m_gridsizer_advanced->Add(new wxStaticText(m_page_advanced, wxID_ANY, wxString("")));
for (unsigned int i = 0; i < m_number_of_extruders; ++i)
m_gridsizer_advanced->Add(new wxStaticText(m_page_advanced, wxID_ANY, wxString("") << i + 1), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
for (unsigned int i = 0; i < m_number_of_extruders; ++i) {
m_gridsizer_advanced->Add(new wxStaticText(m_page_advanced, wxID_ANY, wxString("") << i + 1), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
for (unsigned int j = 0; j < m_number_of_extruders; ++j)
m_gridsizer_advanced->Add(edit_boxes[j][i], 0);
}
auto hsizer = new wxBoxSizer(wxHORIZONTAL);
hsizer->AddSpacer(20);
hsizer->Add(new wxStaticText(m_page_advanced, wxID_ANY, wxString("") << i + 1), 0, wxALIGN_CENTER);
wxWindow* w = new wxWindow(m_page_advanced, wxID_ANY, wxDefaultPosition, icon_size, wxBORDER_SIMPLE);
w->SetCanFocus(false);
w->SetBackgroundColour(m_colours[i]);
hsizer->AddStretchSpacer();
hsizer->Add(w);
m_gridsizer_advanced->Add(hsizer, 1, wxEXPAND);
}
for (unsigned int i = 0; i < m_number_of_extruders; ++i) {
auto hsizer = new wxBoxSizer(wxHORIZONTAL);
wxWindow* w = new wxWindow(m_page_advanced, wxID_ANY, wxDefaultPosition, icon_size, wxBORDER_SIMPLE);
w->SetCanFocus(false);
w->SetBackgroundColour(m_colours[i]);
hsizer->AddSpacer(20);
hsizer->Add(new wxStaticText(m_page_advanced, wxID_ANY, wxString("") << i + 1), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
hsizer->AddStretchSpacer();
hsizer->Add(w);
m_gridsizer_advanced->Add(hsizer, 1, wxEXPAND);
for (unsigned int j = 0; j < m_number_of_extruders; ++j)
m_gridsizer_advanced->Add(edit_boxes[j][i], 0);
}
// collect and format sizer
format_sizer(m_sizer_advanced, m_page_advanced, m_gridsizer_advanced,
@ -237,7 +266,16 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector<float>& matrix, con
for (unsigned int i=0;i<m_number_of_extruders;++i) {
m_old.push_back(new wxSpinCtrl(m_page_simple,wxID_ANY,wxEmptyString,wxDefaultPosition, wxSize(ITEM_WIDTH(), -1),wxSP_ARROW_KEYS|wxALIGN_RIGHT,0,300,extruders[2*i]));
m_new.push_back(new wxSpinCtrl(m_page_simple,wxID_ANY,wxEmptyString,wxDefaultPosition, wxSize(ITEM_WIDTH(), -1),wxSP_ARROW_KEYS|wxALIGN_RIGHT,0,300,extruders[2*i+1]));
gridsizer_simple->Add(new wxStaticText(m_page_simple, wxID_ANY, wxString(_(L("Tool #"))) << i + 1 << ": "), 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
auto hsizer = new wxBoxSizer(wxHORIZONTAL);
wxWindow* w = new wxWindow(m_page_simple, wxID_ANY, wxDefaultPosition, icon_size, wxBORDER_SIMPLE);
w->SetCanFocus(false);
w->SetBackgroundColour(m_colours[i]);
hsizer->Add(w, wxALIGN_CENTER_VERTICAL);
hsizer->AddSpacer(10);
hsizer->Add(new wxStaticText(m_page_simple, wxID_ANY, wxString(_(L("Tool #"))) << i + 1 << ": "), 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
gridsizer_simple->Add(hsizer, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL);
gridsizer_simple->Add(m_old.back(),0);
gridsizer_simple->Add(m_new.back(),0);
}

View File

@ -46,7 +46,7 @@ private:
class WipingPanel : public wxPanel {
public:
WipingPanel(wxWindow* parent, const std::vector<float>& matrix, const std::vector<float>& extruders, wxButton* widget_button);
WipingPanel(wxWindow* parent, const std::vector<float>& matrix, const std::vector<float>& extruders, const std::vector<std::string>& extruder_colours, wxButton* widget_button);
std::vector<float> read_matrix_values();
std::vector<float> read_extruders_values();
void toggle_advanced(bool user_action = false);
@ -59,6 +59,7 @@ private:
std::vector<wxSpinCtrl*> m_old;
std::vector<wxSpinCtrl*> m_new;
std::vector<std::vector<wxTextCtrl*>> edit_boxes;
std::vector<wxColour> m_colours;
unsigned int m_number_of_extruders = 0;
bool m_advanced = false;
wxPanel* m_page_simple = nullptr;
@ -76,7 +77,7 @@ private:
class WipingDialog : public wxDialog {
public:
WipingDialog(wxWindow* parent,const std::vector<float>& matrix, const std::vector<float>& extruders);
WipingDialog(wxWindow* parent, const std::vector<float>& matrix, const std::vector<float>& extruders, const std::vector<std::string>& extruder_colours);
std::vector<float> get_matrix() const { return m_output_matrix; }
std::vector<float> get_extruders() const { return m_output_extruders; }

View File

@ -752,7 +752,7 @@ static bool append_root_node(ObjectDataViewModelNode *parent_node,
if (inst_root_id < 0) {
if ((root_type&itInstanceRoot) ||
(root_type&itLayerRoot) && get_root_idx(parent_node, itInstanceRoot)<0)
( (root_type&itLayerRoot) && get_root_idx(parent_node, itInstanceRoot)<0) )
parent_node->Append(*root_node);
else if (root_type&itLayerRoot)
parent_node->Insert(*root_node, static_cast<unsigned int>(get_root_idx(parent_node, itInstanceRoot)));
@ -1379,7 +1379,12 @@ void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type
type = itUndef;
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
if (!node || node->GetIdx() <-1 || node->GetIdx() == -1 && !(node->GetType() & (itObject | itSettings | itInstanceRoot | itLayerRoot/* | itLayer*/)))
if (!node ||
node->GetIdx() <-1 ||
( node->GetIdx() == -1 &&
!(node->GetType() & (itObject | itSettings | itInstanceRoot | itLayerRoot/* | itLayer*/))
)
)
return;
idx = node->GetIdx();
@ -2187,9 +2192,9 @@ double DoubleSlider::get_double_value(const SelectedSlider& selection)
return 0.0;
if (m_values.size() <= m_higher_value) {
correct_higher_value();
return m_values.back().second;
return m_values.back();
}
return m_values[selection == ssLower ? m_lower_value : m_higher_value].second;
return m_values[selection == ssLower ? m_lower_value : m_higher_value];
}
std::vector<double> DoubleSlider::GetTicksValues() const
@ -2201,7 +2206,7 @@ std::vector<double> DoubleSlider::GetTicksValues() const
for (int tick : m_ticks) {
if (tick > val_size)
break;
values.push_back(m_values[tick].second);
values.push_back(m_values[tick]);
}
return values;
@ -2215,14 +2220,13 @@ void DoubleSlider::SetTicksValues(const std::vector<double>& heights)
const bool was_empty = m_ticks.empty();
m_ticks.clear();
unsigned int i = 0;
for (auto h : heights) {
while (i < m_values.size() && m_values[i].second - epsilon()/*1e-6*/ < h)
++i;
// don't miss last layer if it is
if (i == m_values.size() && fabs(m_values[i-1].second - h) > epsilon())
return;
m_ticks.insert(i-1);
auto it = std::lower_bound(m_values.begin(), m_values.end(), h - epsilon());
if (it == m_values.end())
continue;
m_ticks.insert(it-m_values.begin());
}
if (!was_empty && m_ticks.empty())
@ -2342,13 +2346,14 @@ wxString DoubleSlider::get_label(const SelectedSlider& selection) const
const wxString str = m_values.empty() ?
wxNumberFormatter::ToString(m_label_koef*value, 2, wxNumberFormatter::Style_None) :
wxNumberFormatter::ToString(m_values[value].second, 2, wxNumberFormatter::Style_None);
return wxString::Format("%s\n(%d)", str, m_values.empty() ? value : m_values[value].first);
wxNumberFormatter::ToString(m_values[value], 2, wxNumberFormatter::Style_None);
return wxString::Format("%s\n(%d)", str, m_values.empty() ? value : value+1);
}
void DoubleSlider::draw_thumb_text(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection) const
{
if ((m_is_one_layer || m_higher_value==m_lower_value) && selection != m_selection || !selection)
if ( selection == ssUndef ||
((m_is_one_layer || m_higher_value==m_lower_value) && selection != m_selection) )
return;
wxCoord text_width, text_height;
const wxString label = get_label(selection);
@ -2680,7 +2685,7 @@ void DoubleSlider::correct_lower_value()
else if (m_lower_value > m_max_value)
m_lower_value = m_max_value;
if (m_lower_value >= m_higher_value && m_lower_value <= m_max_value || m_is_one_layer)
if ((m_lower_value >= m_higher_value && m_lower_value <= m_max_value) || m_is_one_layer)
m_higher_value = m_lower_value;
}
@ -2691,7 +2696,7 @@ void DoubleSlider::correct_higher_value()
else if (m_higher_value < m_min_value)
m_higher_value = m_min_value;
if (m_higher_value <= m_lower_value && m_higher_value >= m_min_value || m_is_one_layer)
if ((m_higher_value <= m_lower_value && m_higher_value >= m_min_value) || m_is_one_layer)
m_lower_value = m_higher_value;
}

View File

@ -385,9 +385,9 @@ class ObjectDataViewModel :public wxDataViewModel
{
std::vector<ObjectDataViewModelNode*> m_objects;
std::vector<wxBitmap*> m_volume_bmps;
wxBitmap* m_warning_bmp;
wxBitmap* m_warning_bmp { nullptr };
wxDataViewCtrl* m_ctrl{ nullptr };
wxDataViewCtrl* m_ctrl { nullptr };
public:
ObjectDataViewModel();
@ -720,15 +720,17 @@ public:
const wxString& name = wxEmptyString);
~DoubleSlider() {}
// permissible error for layer height
/* For exporting GCode in GCodeWriter is used XYZF_NUM(val) = PRECISION(val, 3) for XYZ values.
* So, let use same value as a permissible error for layer height.
*/
static double epsilon() { return 0.0011;}
void msw_rescale();
int GetMinValue() const { return m_min_value; }
int GetMaxValue() const { return m_max_value; }
double GetMinValueD() { return m_values.empty() ? 0. : m_values[m_min_value].second; }
double GetMaxValueD() { return m_values.empty() ? 0. : m_values[m_max_value].second; }
double GetMinValueD() { return m_values.empty() ? 0. : m_values[m_min_value]; }
double GetMaxValueD() { return m_values.empty() ? 0. : m_values[m_max_value]; }
int GetLowerValue() const { return m_lower_value; }
int GetHigherValue() const { return m_higher_value; }
int GetActiveValue() const;
@ -744,7 +746,7 @@ public:
void SetKoefForLabels(const double koef) {
m_label_koef = koef;
}
void SetSliderValues(const std::vector<std::pair<int, double>>& values) {
void SetSliderValues(const std::vector<double>& values) {
m_values = values;
}
void ChangeOneLayerLock();
@ -865,7 +867,7 @@ private:
std::vector<wxPen*> m_line_pens;
std::vector<wxPen*> m_segm_pens;
std::set<int> m_ticks;
std::vector<std::pair<int,double>> m_values;
std::vector<double> m_values;
};

View File

@ -65,13 +65,6 @@ new_from_type(CLASS, type)
OUTPUT:
RETVAL
void
make_fill(CLASS, layer_region, out_append)
char* CLASS;
LayerRegion* layer_region;
ExtrusionEntityCollection* out_append;
CODE:
make_fill(*layer_region, *out_append);
%}
};