diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index fbdef29b98..0095f8858d 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 7a99e84f71..c16d764152 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 8bf6c36898..fb79478930 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 4b0a846add..51cc4da9d4 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 78965486bf..81385375b4 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1742,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) @@ -3031,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 83d61c4832..72813810bd 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 9280aa33a4..677d6b8680 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 d4006120d2..0d4b83ecbc 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 9745f23dfe..9e2ec1251b 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -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; } @@ -387,14 +387,14 @@ public: } - 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" + std::to_string((size_t)(255.0 * speed / 100.0)) + "\n"; + m_gcode += "M106 S" + std::to_string(unsigned(255.0 * speed / 100.0)) + "\n"; m_last_fan_speed = speed; return *this; } @@ -417,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; @@ -466,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) @@ -479,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()); } @@ -505,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()); @@ -548,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(); @@ -683,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); @@ -789,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); @@ -898,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 @@ -1078,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; } @@ -1175,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; @@ -1254,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/Layer.cpp b/src/libslic3r/Layer.cpp index a8160867af..399833c699 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 44af8c8bef..c01abbb154 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 530d849072..0cfd974152 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.hpp b/src/libslic3r/Print.hpp index b6d7b678d2..89a5f3e745 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 5236e4e049..ae7241d054 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 465a9d0f9f..6a19edf845 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -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/PrintRegion.cpp b/src/libslic3r/PrintRegion.cpp index fc2bdfa7d1..b3ac6a4a5b 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 3b696212ea..38f21e6cff 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 45c8cdc33b..30d6fc7c3e 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 e0f7e1ea3d..e01b6a9388 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 9544748e93..b60105eb30 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/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 2811a19da9..0a5c21cce4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -308,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; @@ -330,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()) @@ -347,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); @@ -777,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; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 787d220da0..d2451f64eb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -30,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; @@ -99,11 +99,9 @@ private: 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). diff --git a/xs/xsp/Filler.xsp b/xs/xsp/Filler.xsp index 5f04e73480..34a6d33bee 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); %} };