diff --git a/src/admesh/stl.h b/src/admesh/stl.h index 9b1146f8d..117090dd8 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -247,7 +247,7 @@ extern void its_transform(indexed_triangle_set &its, T *trafo3x4) template inline void its_transform(indexed_triangle_set &its, const Eigen::Transform& t) { - const Eigen::Matrix r = t.matrix().template block<3, 3>(0, 0); + //const Eigen::Matrix r = t.matrix().template block<3, 3>(0, 0); for (stl_vertex &v : its.vertices) v = (t * v.template cast()).template cast().eval(); } diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index fbdef29b9..9642f3629 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -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 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 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 group_fills(const Layer &layer) +{ + std::vector surface_fills; + + // Fill in a map of a region & surface to SurfaceFillParams. + std::set set_surface_params; + std::vector> region_to_surface_params(layer.regions().size(), std::vector()); + 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::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 ¶ms : set_surface_params) { + const_cast(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 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 f = std::unique_ptr(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 f = std::unique_ptr(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(layerm->fills.entities[i]) != nullptr); +#endif } } // namespace Slic3r diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index 7a99e84f7..c16d76415 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -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 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 ¶ms) { // Perform offset. diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index 8bf6c3689..fb7947893 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -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; } diff --git a/src/libslic3r/Flow.hpp b/src/libslic3r/Flow.hpp index 4b0a846ad..51cc4da9d 100644 --- a/src/libslic3r/Flow.hpp +++ b/src/libslic3r/Flow.hpp @@ -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. diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index de43bfaec..81385375b 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -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(0, (is_solid_infill(fill->entities.front()->role()) ? region.config().solid_infill_extruder : region.config().infill_extruder) - 1) : - std::max(region.config().perimeter_extruder.value - 1, 0); // Let's recover vector of extruder overrides: - const ExtruderPerCopy* entity_overrides = const_cast(layer_tools).wiping_extrusions().get_extruder_overrides(fill, correct_extruder_id, (int)layer_to_print.object()->copies().size()); + const ExtruderPerCopy* entity_overrides = const_cast(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::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; diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 83d61c483..72813810b 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -246,7 +246,7 @@ protected: std::vector 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 by_region; // all extrusions for this island, grouped by regions diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 9280aa33a..677d6b868 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -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(), [<](const Layer* lay) { return std::abs(lt.print_z - lay->print_z)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* WipingExtrusions::get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, int num_of_copies) +const std::vector* 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()) diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp index d4006120d..0d4b83ecb 100644 --- a/src/libslic3r/GCode/ToolOrdering.hpp +++ b/src/libslic3r/GCode/ToolOrdering.hpp @@ -24,7 +24,7 @@ public: } // This is called from GCode::process_layer - see implementation for further comments: - const std::vector* get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, int num_of_copies); + const std::vector* 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); } diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index da4c6aa6e..9e2ec1251 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -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>& 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& 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::prime( const std::vector &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; diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index fab75c5e6..63aedcba3 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -7,21 +7,21 @@ #include #include -#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>& 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> 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( diff --git a/src/libslic3r/GCodeTimeEstimator.cpp b/src/libslic3r/GCodeTimeEstimator.cpp index 00b409344..4693ba9e6 100644 --- a/src/libslic3r/GCodeTimeEstimator.cpp +++ b/src/libslic3r/GCodeTimeEstimator.cpp @@ -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; } diff --git a/src/libslic3r/GCodeTimeEstimator.hpp b/src/libslic3r/GCodeTimeEstimator.hpp index dd5d14b57..d9f3bc211 100644 --- a/src/libslic3r/GCodeTimeEstimator.hpp +++ b/src/libslic3r/GCodeTimeEstimator.hpp @@ -213,9 +213,19 @@ namespace Slic3r { typedef std::map MovesStatsMap; #endif // ENABLE_MOVE_STATS + public: typedef std::pair G1LineIdToBlockId; typedef std::vector 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& 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(); diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index a8160867a..399833c69 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -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(layerm->fills.entities[i]) != NULL); -#endif - } -} - void Layer::export_region_slices_to_svg(const char *path) const { BoundingBox bbox; diff --git a/src/libslic3r/PerimeterGenerator.hpp b/src/libslic3r/PerimeterGenerator.hpp index 44af8c8be..c01abbb15 100644 --- a/src/libslic3r/PerimeterGenerator.hpp +++ b/src/libslic3r/PerimeterGenerator.hpp @@ -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: diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index 530d84907..0cfd97415 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -108,7 +108,6 @@ static inline bool opts_equal(const DynamicConfig &config_old, const DynamicConf std::vector PlaceholderParser::config_diff(const DynamicPrintConfig &rhs) { - const ConfigDef *def = rhs.def(); std::vector 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 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)) { diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 796215781..9d4df56d0 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1228,24 +1228,35 @@ std::string Print::validate() const if (has_custom_layering) { const std::vector &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 &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; + } } } } diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index b6d7b678d..89a5f3e74 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -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; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 5236e4e04..ae7241d05 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -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); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 015b2bde7..6a19edf84 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -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 { diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index e19bceeb7..75145145d 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -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 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 diff --git a/src/libslic3r/PrintRegion.cpp b/src/libslic3r/PrintRegion.cpp index fc2bdfa7d..b3ac6a4a5 100644 --- a/src/libslic3r/PrintRegion.cpp +++ b/src/libslic3r/PrintRegion.cpp @@ -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 &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); } diff --git a/src/libslic3r/SLA/SLAAutoSupports.hpp b/src/libslic3r/SLA/SLAAutoSupports.hpp index 3b696212e..38f21e6cf 100644 --- a/src/libslic3r/SLA/SLAAutoSupports.hpp +++ b/src/libslic3r/SLA/SLAAutoSupports.hpp @@ -185,8 +185,6 @@ private: SLAAutoSupports::Config m_config; - float m_supports_force_total = 0.f; - void process(const std::vector& slices, const std::vector& 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& points) const; diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 45c8cdc33..30d6fc7c3 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -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) { diff --git a/src/libslic3r/Surface.hpp b/src/libslic3r/Surface.hpp index e0f7e1ea3..e01b6a938 100644 --- a/src/libslic3r/Surface.hpp +++ b/src/libslic3r/Surface.hpp @@ -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 diff --git a/src/libslic3r/SurfaceCollection.hpp b/src/libslic3r/SurfaceCollection.hpp index 9544748e9..b60105eb3 100644 --- a/src/libslic3r/SurfaceCollection.hpp +++ b/src/libslic3r/SurfaceCollection.hpp @@ -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; diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 2916d0177..8094cdde1 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -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; diff --git a/src/slic3r/GUI/BedShapeDialog.cpp b/src/slic3r/GUI/BedShapeDialog.cpp index a9be260bd..90fc0ff80 100644 --- a/src/slic3r/GUI/BedShapeDialog.cpp +++ b/src/slic3r/GUI/BedShapeDialog.cpp @@ -446,7 +446,7 @@ void BedShapePanel::update_shape() auto twopi = 2 * PI; auto edges = 72; std::vector 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))); } diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 454b4874f..9750095c9 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -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(m_value))) { @@ -444,7 +444,7 @@ void TextCtrl::disable() { dynamic_cast(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; } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 71bacd815..0494af3d5 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -845,22 +845,23 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_values(const GCodePrevie { auto& config = wxGetApp().preset_bundle->project_config; const std::vector& color_print_values = config.option("colorprint_heights")->values; - const size_t values_cnt = color_print_values.size(); - if (values_cnt > 0) { + + if (!color_print_values.empty()) { std::vector 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(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(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 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& 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; iwipe_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) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 0beef094b..879584528 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -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; diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp index 59a34d8cd..5fbefcc6e 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -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"); diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index 4fdf12489..55ca5f723 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -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(); } diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp index 63387bf2d..caadec61c 100644 --- a/src/slic3r/GUI/GLToolbar.cpp +++ b/src/slic3r/GUI/GLToolbar.cpp @@ -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(); diff --git a/src/slic3r/GUI/GLToolbar.hpp b/src/slic3r/GUI/GLToolbar.hpp index 527317e58..07da836fc 100644 --- a/src/slic3r/GUI/GLToolbar.hpp +++ b/src/slic3r/GUI/GLToolbar.hpp @@ -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); diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index 826f2d6fc..f94372667 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -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 } } diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 1b2da4769..80c02ea78 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -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(); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 20760e2bc..b08f0a948 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -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> ADD_VOLUME_MENU_ITEMS = { +static std::vector> 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 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() diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp index c90e1e4ed..0c10c5460 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp @@ -116,7 +116,7 @@ bool ObjectSettings::update_settings_list() auto optgroup = std::make_shared(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 \ No newline at end of file +} //namespace Slic3r diff --git a/src/slic3r/GUI/GUI_ObjectSettings.hpp b/src/slic3r/GUI/GUI_ObjectSettings.hpp index 61d90600b..a5724811a 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.hpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.hpp @@ -5,11 +5,11 @@ #include #include #include "wxExtensions.hpp" -#include "libslic3r/PrintConfig.hpp" class wxBoxSizer; namespace Slic3r { +class DynamicPrintConfig; namespace GUI { class ConfigOptionsGroup; diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 2b9da6aa0..7c761ed5f 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -640,9 +640,10 @@ void Preview::update_double_slider(const std::vector& 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> values; - fill_slider_values(values, layers_z); - m_slider->SetSliderValues(values); + std::vector &ticks_from_config = (wxGetApp().preset_bundle->project_config.option("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& layers_z, bool kee } m_slider->SetSelectionSpan(idx_low, idx_high); - const auto& config = wxGetApp().preset_bundle->project_config; - const std::vector &ticks_from_config = (config.option("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& layers_z, bool kee m_slider->EnableTickManipulation(color_print_enable); } -void Preview::fill_slider_values(std::vector> &values, +void Preview::check_slider_values(std::vector& ticks_from_config, const std::vector &layers_z) { - values.clear(); - for (int i = 0; i < layers_z.size(); ++i) - { - values.push_back(std::pair(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 &ticks_from_config = (wxGetApp().preset_bundle->project_config.option("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) diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index 401b17a4b..08d5991b4 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -155,7 +155,7 @@ private: // Create/Update/Reset double slider on 3dPreview void create_double_slider(); void update_double_slider(const std::vector& layers_z, bool keep_z_range = false); - void fill_slider_values(std::vector> &values, + void check_slider_values(std::vector &ticks_from_config, const std::vector &layers_z); void reset_double_slider(); // update DoubleSlider after keyDown in canvas diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index 18053dcd6..da3042779 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -69,7 +69,6 @@ public: enum EState { Off, - Hover, On, Num_States }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp index c69d64134..9cd2ab6bb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp @@ -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; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index 8733c9a11..c856e5465 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -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) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index bf540cb00..a685fb774 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -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; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 28d569761..0a5c21cce 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -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 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 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()) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index feb2455cb..d2451f64e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -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 #include @@ -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& 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; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 1528a4bcb..00ca9ee05 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -29,9 +29,49 @@ GLGizmosManager::GLGizmosManager(GLCanvas3D& parent) { } -GLGizmosManager::~GLGizmosManager() +std::vector GLGizmosManager::get_selectable_idxs() const { - reset(); + std::vector out; + for (size_t i=0; iis_selectable()) + out.push_back(i); + return out; +} + +std::vector GLGizmosManager::get_activable_idxs() const +{ + std::vector out; + for (size_t i=0; iis_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 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(it->second)->get_displacement() : Vec3d::Zero(); + return dynamic_cast(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(it->second)->get_scale() : Vec3d::Ones(); + return dynamic_cast(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(it->second)->set_scale(scale); + dynamic_cast(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(it->second)->get_offset() : Vec3d::Zero(); + return dynamic_cast(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(it->second)->get_rotation() : Vec3d::Zero(); + return dynamic_cast(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(it->second)->set_rotation(rotation); + dynamic_cast(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(it->second)->get_flattening_normal() : Vec3d::Zero(); + return dynamic_cast(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(it->second)->set_flattening_data(model_object); + dynamic_cast(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(it->second)->set_sla_support_data(model_object, m_parent.get_selection()); + dynamic_cast(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(it->second)->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); - - return false; + return dynamic_cast(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(it->second)->get_sla_clipping_plane(); - - return ClippingPlane::ClipsNothing(); + return dynamic_cast(m_gizmos[SlaSupports].get())->get_sla_clipping_plane(); } bool GLGizmosManager::wants_reslice_supports_on_undo() const { return (m_current == SlaSupports - && dynamic_cast(m_gizmos.at(SlaSupports))->has_backend_supports()); + && dynamic_cast(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(get_current()); + GLGizmoSlaSupports* gizmo = dynamic_cast(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(get_current())->is_in_editing_mode()) + if ((m_current == SlaSupports) && ((keyCode == WXK_SHIFT) || (keyCode == WXK_ALT)) + && dynamic_cast(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(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(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; idxsecond == 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 filenames; - for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it) + for (size_t idx=0; idxsecond != 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 &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 &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) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index c0adeb957..f649c98b2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -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 GizmosMap; - GizmosMap m_gizmos; + std::vector> 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 get_selectable_idxs() const; + std::vector 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 @@ -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; }; diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index aa1e3d500..28bd0242b 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -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; diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index c17569c11..c032aac72 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -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; } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 66985b4e4..141b33d01 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -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 &init_matrix = (config.option("wiping_volumes_matrix"))->values; - const std::vector &init_extruders = (config.option("wiping_volumes_extruders"))->values; + auto &project_config = wxGetApp().preset_bundle->project_config; + const std::vector &init_matrix = (project_config.option("wiping_volumes_matrix"))->values; + const std::vector &init_extruders = (project_config.option("wiping_volumes_extruders"))->values; - WipingDialog dlg(parent, cast(init_matrix), cast(init_extruders)); + const DynamicPrintConfig* config = &wxGetApp().preset_bundle->printers.get_edited_preset().config; + const std::vector &extruder_colours = (config->option("extruder_colour"))->values; + + WipingDialog dlg(parent, cast(init_matrix), cast(init_extruders), extruder_colours); if (dlg.ShowModal() == wxID_OK) { std::vector matrix = dlg.get_matrix(); std::vector extruders = dlg.get_extruders(); - (config.option("wiping_volumes_matrix"))->values = std::vector(matrix.begin(), matrix.end()); - (config.option("wiping_volumes_extruders"))->values = std::vector(extruders.begin(), extruders.end()); + (project_config.option("wiping_volumes_matrix"))->values = std::vector(matrix.begin(), matrix.end()); + (project_config.option("wiping_volumes_extruders"))->values = std::vector(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(model_object->materials_count()))); @@ -2284,20 +2285,20 @@ std::vector Plater::priv::load_files(const std::vector& 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 Plater::priv::load_files(const std::vector& 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) { diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index 79d49f13a..3acff7689 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -697,6 +697,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool config.option("default_sla_print_profile", true); config.option("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; } } diff --git a/src/slic3r/GUI/PresetHints.cpp b/src/slic3r/GUI/PresetHints.cpp index 8b7d54538..a02772c4d 100644 --- a/src/slic3r/GUI/PresetHints.cpp +++ b/src/slic3r/GUI/PresetHints.cpp @@ -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); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 9c1a84615..40fbbbac6 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -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 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 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 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) { diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index d9cf56f03..77bd613d5 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -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("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("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("fill_density")->value == 100) { - auto fill_pattern = m_config->option>("fill_pattern")->value; - std::string str_fill_pattern = ""; - t_config_enum_values map_names = m_config->option>("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 &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(ipRectilinear)); - fill_density = 100; - } - else - fill_density = m_presets->get_selected_preset().config.option("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("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--; diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index f57558c45..ee6937652 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -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")) {} diff --git a/src/slic3r/GUI/WipeTowerDialog.cpp b/src/slic3r/GUI/WipeTowerDialog.cpp index 894b1ee62..460683f77 100644 --- a/src/slic3r/GUI/WipeTowerDialog.cpp +++ b/src/slic3r/GUI/WipeTowerDialog.cpp @@ -1,6 +1,7 @@ #include #include #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& matrix, const std::vector& extruders) +WipingDialog::WipingDialog(wxWindow* parent, const std::vector& matrix, const std::vector& extruders, const std::vector& 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& matrix, const std::vector& extruders, wxButton* widget_button) +WipingPanel::WipingPanel(wxWindow* parent, const std::vector& matrix, const std::vector& extruders, const std::vector& 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& 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& 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& matrix, con for (unsigned int i=0;iAdd(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); } diff --git a/src/slic3r/GUI/WipeTowerDialog.hpp b/src/slic3r/GUI/WipeTowerDialog.hpp index d858062da..84b9921de 100644 --- a/src/slic3r/GUI/WipeTowerDialog.hpp +++ b/src/slic3r/GUI/WipeTowerDialog.hpp @@ -46,7 +46,7 @@ private: class WipingPanel : public wxPanel { public: - WipingPanel(wxWindow* parent, const std::vector& matrix, const std::vector& extruders, wxButton* widget_button); + WipingPanel(wxWindow* parent, const std::vector& matrix, const std::vector& extruders, const std::vector& extruder_colours, wxButton* widget_button); std::vector read_matrix_values(); std::vector read_extruders_values(); void toggle_advanced(bool user_action = false); @@ -59,6 +59,7 @@ private: std::vector m_old; std::vector m_new; std::vector> edit_boxes; + std::vector 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& matrix, const std::vector& extruders); + WipingDialog(wxWindow* parent, const std::vector& matrix, const std::vector& extruders, const std::vector& extruder_colours); std::vector get_matrix() const { return m_output_matrix; } std::vector get_extruders() const { return m_output_extruders; } diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 06e9a7f90..71eaa3fc8 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -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(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 DoubleSlider::GetTicksValues() const @@ -2201,7 +2206,7 @@ std::vector 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& 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; } diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 51faffda7..54d1bf7cb 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -385,9 +385,9 @@ class ObjectDataViewModel :public wxDataViewModel { std::vector m_objects; std::vector 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>& values) { + void SetSliderValues(const std::vector& values) { m_values = values; } void ChangeOneLayerLock(); @@ -865,7 +867,7 @@ private: std::vector m_line_pens; std::vector m_segm_pens; std::set m_ticks; - std::vector> m_values; + std::vector m_values; }; diff --git a/xs/xsp/Filler.xsp b/xs/xsp/Filler.xsp index 5f04e7348..34a6d33be 100644 --- a/xs/xsp/Filler.xsp +++ b/xs/xsp/Filler.xsp @@ -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); %} };