Esempio n. 1
0
Flow
PrintRegion::flow(FlowRole role, double layer_height, bool bridge, bool first_layer, double width, const PrintObject &object) const
{
    ConfigOptionFloatOrPercent config_width;
    if (width != -1) {
        // use the supplied custom width, if any
        config_width.value = width;
        config_width.percent = false;
    } else {
        // otherwise, get extrusion width from configuration
        // (might be an absolute value, or a percent value, or zero for auto)
        if (first_layer && this->_print->config.first_layer_extrusion_width.value > 0) {
            config_width = this->_print->config.first_layer_extrusion_width;
        } else if (role == frExternalPerimeter) {
            config_width = this->config.external_perimeter_extrusion_width;
        } else if (role == frPerimeter) {
            config_width = this->config.perimeter_extrusion_width;
        } else if (role == frInfill) {
            config_width = this->config.infill_extrusion_width;
        } else if (role == frSolidInfill) {
            config_width = this->config.solid_infill_extrusion_width;
        } else if (role == frTopSolidInfill) {
            config_width = this->config.top_infill_extrusion_width;
        } else {
            CONFESS("Unknown role");
        }
    }
    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;  // 1-based
    if (role == frPerimeter || role == frExternalPerimeter) {
        extruder = this->config.perimeter_extruder;
    } else if (role == frInfill) {
        extruder = this->config.infill_extruder;
    } else if (role == frSolidInfill || role == frTopSolidInfill) {
        extruder = this->config.solid_infill_extruder;
    } else {
        CONFESS("Unknown role $role");
    }
    double nozzle_diameter = this->_print->config.nozzle_diameter.get_at(extruder-1);
    
    return Flow::new_from_config_width(role, config_width, nozzle_diameter, layer_height, bridge ? (float)this->config.bridge_flow_ratio : 0.0);
}
Esempio n. 2
0
void
Surface::from_SV_check(SV* surface_sv)
{
    if (!sv_isa(surface_sv, perl_class_name(this)) && !sv_isa(surface_sv, perl_class_name_ref(this)))
        CONFESS("Not a valid %s object", perl_class_name(this));
    // a XS Surface was supplied
    *this = *(Surface *)SvIV((SV*)SvRV( surface_sv ));
}
Esempio n. 3
0
void
Polygon::from_SV_check(SV* poly_sv)
{
    if (sv_isobject(poly_sv) && !sv_isa(poly_sv, perl_class_name(this)) && !sv_isa(poly_sv, perl_class_name_ref(this)))
        CONFESS("Not a valid %s object", perl_class_name(this));
    
    MultiPoint::from_SV_check(poly_sv);
}
Esempio n. 4
0
/* This constructor builds a Flow object from a given centerline spacing. */
Flow
Flow::new_from_spacing(float spacing, float nozzle_diameter, float height, bool bridge) {
    // we need layer height unless it's a bridge
    if (height <= 0 && !bridge) CONFESS("Invalid flow height supplied to new_from_spacing()");

    float w = Flow::_width_from_spacing(spacing, nozzle_diameter, height, bridge);
    return Flow(w, height, nozzle_diameter, bridge);
}
Esempio n. 5
0
void
Line::from_SV_check(SV* line_sv)
{
    if (sv_isobject(line_sv) && (SvTYPE(SvRV(line_sv)) == SVt_PVMG)) {
        if (!sv_isa(line_sv, perl_class_name(this)) && !sv_isa(line_sv, perl_class_name_ref(this)))
            CONFESS("Not a valid %s object", perl_class_name(this));
        *this = *(Line*)SvIV((SV*)SvRV( line_sv ));
    } else {
        this->from_SV(line_sv);
    }
}
Esempio n. 6
0
BoundingBox3Base<PointClass>::BoundingBox3Base(const std::vector<PointClass> &points)
    : BoundingBoxBase<PointClass>(points)
{
    if (points.empty()) CONFESS("Empty point set supplied to BoundingBox3Base constructor");
    typename std::vector<PointClass>::const_iterator it = points.begin();
    this->min.z = this->max.z = it->z;
    for (++it; it != points.end(); ++it) {
        this->min.z = std::min(it->z, this->min.z);
        this->max.z = std::max(it->z, this->max.z);
    }
}
Esempio n. 7
0
BoundingBoxf3
ModelObject::raw_bounding_box() const
{
    BoundingBoxf3 bb;
    for (ModelVolumePtrs::const_iterator v = this->volumes.begin(); v != this->volumes.end(); ++v) {
        if ((*v)->modifier) continue;
        if (this->instances.empty()) CONFESS("Can't call raw_bounding_box() with no instances");
        bb.merge(this->instances.front()->transform_mesh_bounding_box(&(*v)->mesh, true));
    }
    return bb;
}
Esempio n. 8
0
void
Line::from_SV_check(SV* line_sv)
{
    if (sv_isobject(line_sv) && (SvTYPE(SvRV(line_sv)) == SVt_PVMG)) {
        if (!sv_isa(line_sv, "Slic3r::Line") && !sv_isa(line_sv, "Slic3r::Line::Ref"))
            CONFESS("Not a valid Slic3r::Line object");
        *this = *(Line*)SvIV((SV*)SvRV( line_sv ));
    } else {
        this->from_SV(line_sv);
    }
}
Esempio n. 9
0
Polyline*
Polygon::split_at(const Point &point) const
{
    // find index of point
    for (Points::const_iterator it = this->points.begin(); it != this->points.end(); ++it) {
        if (it->coincides_with(point))
            return this->split_at_index(it - this->points.begin());
    }
    CONFESS("Point not found");
    return NULL;
}
Esempio n. 10
0
void
Point::from_SV_check(SV* point_sv)
{
    if (sv_isobject(point_sv) && (SvTYPE(SvRV(point_sv)) == SVt_PVMG)) {
        if (!sv_isa(point_sv, perl_class_name(this)) && !sv_isa(point_sv, perl_class_name_ref(this)))
            CONFESS("Not a valid %s object (got %s)", perl_class_name(this), HvNAME(SvSTASH(SvRV(point_sv))));
        *this = *(Point*)SvIV((SV*)SvRV( point_sv ));
    } else {
        this->from_SV(point_sv);
    }
}
Esempio n. 11
0
Point
PolylineCollection::leftmost_point() const
{
    if (this->polylines.empty()) CONFESS("leftmost_point() called on empty PolylineCollection");
    Point p = this->polylines.front().leftmost_point();
    for (Polylines::const_iterator it = this->polylines.begin() + 1; it != this->polylines.end(); ++it) {
        Point p2 = it->leftmost_point();
        if (p2.x < p.x) p = p2;
    }
    return p;
}
Esempio n. 12
0
Point PolylineCollection::leftmost_point(const Polylines &polylines)
{
    if (polylines.empty()) CONFESS("leftmost_point() called on empty PolylineCollection");
    Polylines::const_iterator it = polylines.begin();
    Point p = it->leftmost_point();
    for (++ it; it != polylines.end(); ++it) {
        Point p2 = it->leftmost_point();
        if (p2.x < p.x) 
            p = p2;
    }
    return p;
}
Esempio n. 13
0
BoundingBoxBase<PointClass>::BoundingBoxBase(const std::vector<PointClass> &points)
{
    if (points.empty()) CONFESS("Empty point set supplied to BoundingBoxBase constructor");
    typename std::vector<PointClass>::const_iterator it = points.begin();
    this->min.x = this->max.x = it->x;
    this->min.y = this->max.y = it->y;
    for (++it; it != points.end(); ++it) {
        this->min.x = std::min(it->x, this->min.x);
        this->min.y = std::min(it->y, this->min.y);
        this->max.x = std::max(it->x, this->max.x);
        this->max.y = std::max(it->y, this->max.y);
    }
    this->defined = true;
}
Esempio n. 14
0
std::string
GCode::extrude(const ExtrusionEntity &entity, std::string description, double speed, int partNum)
{
    std::string gcode = ";start extrusion\n";
    if (const ExtrusionPath* path = dynamic_cast<const ExtrusionPath*>(&entity)) {
        gcode += this->extrude(*path, description, speed);
    } else if (const ExtrusionLoop* loop = dynamic_cast<const ExtrusionLoop*>(&entity)) {
        gcode += this->extrude(*loop, description, speed);
    } else {
        CONFESS("Invalid argument supplied to extrude()");
        return "";
    }
    gcode += ";end extrusion\n";
    return gcode;
}
Esempio n. 15
0
void
ModelObject::raw_bounding_box(BoundingBoxf3* bb) const
{
    for (ModelVolumePtrs::const_iterator v = this->volumes.begin(); v != this->volumes.end(); ++v) {
        if ((*v)->modifier) continue;
        TriangleMesh mesh = (*v)->mesh;
        
        if (this->instances.empty()) CONFESS("Can't call raw_bounding_box() with no instances");
        this->instances.front()->transform_mesh(&mesh, true);
        
        BoundingBoxf3 mbb;
        mesh.bounding_box(&mbb);
        bb->merge(mbb);
    }
}
Esempio n. 16
0
TriangleMeshPtrs
TriangleMesh::split() const
{
    TriangleMeshPtrs meshes;
    std::set<int> seen_facets;
    
    // we need neighbors
    if (!this->repaired) CONFESS("split() requires repair()");
    
    // loop while we have remaining facets
    while (1) {
        // get the first facet
        std::queue<int> facet_queue;
        std::deque<int> facets;
        for (int facet_idx = 0; facet_idx < this->stl.stats.number_of_facets; facet_idx++) {
            if (seen_facets.find(facet_idx) == seen_facets.end()) {
                // if facet was not seen put it into queue and start searching
                facet_queue.push(facet_idx);
                break;
            }
        }
        if (facet_queue.empty()) break;
        
        while (!facet_queue.empty()) {
            int facet_idx = facet_queue.front();
            facet_queue.pop();
            if (seen_facets.find(facet_idx) != seen_facets.end()) continue;
            facets.push_back(facet_idx);
            for (int j = 0; j <= 2; j++) {
                facet_queue.push(this->stl.neighbors_start[facet_idx].neighbor[j]);
            }
            seen_facets.insert(facet_idx);
        }
        
        TriangleMesh* mesh = new TriangleMesh;
        meshes.push_back(mesh);
        mesh->stl.stats.type = inmemory;
        mesh->stl.stats.number_of_facets = facets.size();
        mesh->stl.stats.original_num_facets = mesh->stl.stats.number_of_facets;
        stl_allocate(&mesh->stl);
        
        for (std::deque<int>::const_iterator facet = facets.begin(); facet != facets.end(); facet++) {
            mesh->stl.facet_start[facet - facets.begin()] = this->stl.facet_start[*facet];
        }
    }
    
    return meshes;
}
Esempio n. 17
0
/* This constructor builds a Flow object from an extrusion width config setting
   and other context properties. */
Flow
Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height, float bridge_flow_ratio) {
    // we need layer height unless it's a bridge
    if (height <= 0 && bridge_flow_ratio == 0) CONFESS("Invalid flow height supplied to new_from_config_width()");
    
    float w;
    if (bridge_flow_ratio > 0) {
        // if bridge flow was requested, calculate bridge width
        w = Flow::_bridge_width(nozzle_diameter, bridge_flow_ratio);
    } else if (!width.percent && width.value == 0) {
        // if user left option to 0, calculate a sane default width
        w = Flow::_auto_width(role, nozzle_diameter, height);
    } else {
        // if user set a manual value, use it
        w = width.get_abs_value(height);
    }
    
    return Flow(w, height, nozzle_diameter, bridge_flow_ratio > 0);
}
void
ExtrusionLoop::split_at_vertex(const Point &point)
{
    for (ExtrusionPaths::iterator path = this->paths.begin(); path != this->paths.end(); ++path) {
        int idx = path->polyline.find_point(point);
        if (idx != -1) {
            if (this->paths.size() == 1) {
                // just change the order of points
                path->polyline.points.insert(path->polyline.points.end(), path->polyline.points.begin() + 1, path->polyline.points.begin() + idx + 1);
                path->polyline.points.erase(path->polyline.points.begin(), path->polyline.points.begin() + idx);
            } else {
                // if we have multiple paths we assume they have different types, so no need to
                // check for continuity as we do for the single path case above
                
                // new paths list starts with the second half of current path
                ExtrusionPaths new_paths;
                {
                    ExtrusionPath p = *path;
                    p.polyline.points.erase(p.polyline.points.begin(), p.polyline.points.begin() + idx);
                    if (p.polyline.is_valid()) new_paths.push_back(p);
                }
            
                // then we add all paths until the end of current path list
                new_paths.insert(new_paths.end(), this->paths.begin(), path);  // not including this path
            
                // then we add all paths since the beginning of current list up to the previous one
                new_paths.insert(new_paths.end(), path+1, this->paths.end());  // not including this path
            
                // finally we add the first half of current path
                {
                    ExtrusionPath p = *path;
                    p.polyline.points.erase(p.polyline.points.begin() + idx + 1, p.polyline.points.end());
                    if (p.polyline.is_valid()) new_paths.push_back(p);
                }
                // we can now override the old path list with the new one and stop looping
                this->paths = new_paths;
            }
            return;
        }
    }
    CONFESS("Point not found");
}
Esempio n. 19
0
void
ConfigBase::apply(const ConfigBase &other, bool ignore_nonexistent) {
    // get list of option keys to apply
    t_config_option_keys opt_keys = other.keys();
    
    // loop through options and apply them
    for (t_config_option_keys::const_iterator it = opt_keys.begin(); it != opt_keys.end(); ++it) {
        ConfigOption* my_opt = this->option(*it, true);
        if (my_opt == NULL) {
            if (ignore_nonexistent == false) throw "Attempt to apply non-existent option";
            continue;
        }
        
        // not the most efficient way, but easier than casting pointers to subclasses
        bool res = my_opt->deserialize( other.option(*it)->serialize() );
        if (!res) {
            std::string error = "Unexpected failure when deserializing serialized value for " + *it;
            CONFESS(error.c_str());
        }
    }
}
Esempio n. 20
0
/*  duplicate the entire model preserving instance relative positions */
void
Model::duplicate(size_t copies_num, coordf_t dist, const BoundingBoxf* bb)
{
    Pointfs model_sizes(copies_num-1, this->bounding_box().size());
    Pointfs positions;
    if (! this->_arrange(model_sizes, dist, bb, positions))
        CONFESS("Cannot duplicate part as the resulting objects would not fit on the print bed.\n");

    // note that this will leave the object count unaltered

    for (ModelObjectPtrs::const_iterator o = this->objects.begin(); o != this->objects.end(); ++o) {
        // make a copy of the pointers in order to avoid recursion when appending their copies
        ModelInstancePtrs instances = (*o)->instances;
        for (ModelInstancePtrs::const_iterator i = instances.begin(); i != instances.end(); ++i) {
            for (Pointfs::const_iterator pos = positions.begin(); pos != positions.end(); ++pos) {
                ModelInstance* instance = (*o)->add_instance(**i);
                instance->offset.translate(*pos);
            }
        }
        (*o)->invalidate_bounding_box();
    }
}
Esempio n. 21
0
static gdouble
spectrum_ramp_wait(struct spectrum_iterator* self)
{
    CONFESS("0x%x: wait idx %d", self, self->idx_linear);
    return (gdouble)(*(self->idx));
}
 Polyline as_polyline() const {
     CONFESS("Calling as_polyline() on a ExtrusionEntityCollection");
     return Polyline();
 };
Esempio n. 23
0
Polyline::operator Line() const
{
    if (this->points.size() > 2) CONFESS("Can't convert polyline with more than two points to a line");
    return Line(this->points.front(), this->points.back());
}
Esempio n. 24
0
std::string
GCode::_extrude(ExtrusionPath path, std::string description, double speed)
{
    path.simplify(SCALED_RESOLUTION);
    
    std::string gcode;
    
    // go to first point of extrusion path
    if (!this->_last_pos_defined || !this->_last_pos.coincides_with(path.first_point())) {
        gcode += this->travel_to(
            path.first_point(),
            path.role,
            "move to first " + description + " point"
        );
    }
    
    // compensate retraction
    gcode += this->unretract();
    
    // adjust acceleration
    {
        double acceleration;
        if (this->config.first_layer_acceleration.value > 0 && this->first_layer) {
            acceleration = this->config.first_layer_acceleration.value;
        } else if (this->config.perimeter_acceleration.value > 0 && path.is_perimeter()) {
            acceleration = this->config.perimeter_acceleration.value;
        } else if (this->config.bridge_acceleration.value > 0 && path.is_bridge()) {
            acceleration = this->config.bridge_acceleration.value;
        } else if (this->config.infill_acceleration.value > 0 && path.is_infill()) {
            acceleration = this->config.infill_acceleration.value;
        } else {
            acceleration = this->config.default_acceleration.value;
        }
        gcode += this->writer.set_acceleration(acceleration);
    }
    
    // calculate extrusion length per distance unit
    double e_per_mm = this->writer.extruder()->e_per_mm3 * path.mm3_per_mm;
    if (this->writer.extrusion_axis().empty()) e_per_mm = 0;
    
    // set speed
    if (speed == -1) {
        if (path.role == erPerimeter) {
            speed = this->config.get_abs_value("perimeter_speed");
        } else if (path.role == erExternalPerimeter) {
            speed = this->config.get_abs_value("external_perimeter_speed");
        } else if (path.role == erOverhangPerimeter || path.role == erBridgeInfill) {
            speed = this->config.get_abs_value("bridge_speed");
        } else if (path.role == erInternalInfill) {
            speed = this->config.get_abs_value("infill_speed");
        } else if (path.role == erSolidInfill) {
            speed = this->config.get_abs_value("solid_infill_speed");
        } else if (path.role == erTopSolidInfill) {
            speed = this->config.get_abs_value("top_solid_infill_speed");
        } else if (path.role == erGapFill) {
            speed = this->config.get_abs_value("gap_fill_speed");
        } else {
            CONFESS("Invalid speed");
        }
    }
    if (this->first_layer) {
        speed = this->config.get_abs_value("first_layer_speed", speed);
    }
    if (this->volumetric_speed != 0 && speed == 0) {
        speed = this->volumetric_speed / path.mm3_per_mm;
    }
    if (this->config.max_volumetric_speed.value > 0) {
        // cap speed with max_volumetric_speed anyway (even if user is not using autospeed)
        speed = std::min(
            speed,
            this->config.max_volumetric_speed.value / path.mm3_per_mm
        );
    }
    double F = speed * 60;  // convert mm/sec to mm/min
    
    // extrude arc or line
    if (path.is_bridge() && this->enable_cooling_markers)
        gcode += ";_BRIDGE_FAN_START\n";
    if (lowerSpeed) {
        gcode += this->writer.set_speed(600, "", this->enable_cooling_markers ? ";_EXTRUDE_SET_SPEED" : "");
    } else {
        gcode += this->writer.set_speed(F, "", this->enable_cooling_markers ? ";_EXTRUDE_SET_SPEED" : "");
    }
    double path_length = 0;
    {
        std::string comment = this->config.gcode_comments ? description : "";
        Lines lines = path.polyline.lines();
        for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line) {
            const double line_length = line->length() * SCALING_FACTOR;
            path_length += line_length;
                
            gcode += this->writer.extrude_to_xy(
                this->point_to_gcode(line->b),
                e_per_mm * line_length,
                comment
            );
            if (path_length > 10 && lowerSpeed) {
                lowerSpeed = false;
                gcode += this->writer.set_speed(F, "", this->enable_cooling_markers ? ";_EXTRUDE_SET_SPEED" : "");
            }
        }
        lowerSpeed = false;
    }
    if (this->wipe.enable) {
        this->wipe.path = path.polyline;
        this->wipe.path.reverse();
    }
    if (path.is_bridge() && this->enable_cooling_markers)
        gcode += ";_BRIDGE_FAN_END\n";
    
    this->set_last_pos(path.last_point());
    
    if (this->config.cooling)
        this->elapsed_time += path_length / F * 60;
    
    return gcode;
}