Example #1
0
std::string
Wipe::wipe(GCode &gcodegen, bool toolchange)
{
    std::string gcode;
    
    /*  Reduce feedrate a bit; travel speed is often too high to move on existing material.
        Too fast = ripping of existing material; too slow = short wipe path, thus more blob.  */
    double wipe_speed = gcodegen.writer.config.travel_speed.value * 0.8;
    
    // get the retraction length
    double length = toolchange
        ? gcodegen.writer.extruder()->retract_length_toolchange()
        : gcodegen.writer.extruder()->retract_length();
    
    if (length > 0) {
        /*  Calculate how long we need to travel in order to consume the required
            amount of retraction. In other words, how far do we move in XY at wipe_speed
            for the time needed to consume retract_length at retract_speed?  */
        double wipe_dist = scale_(length / gcodegen.writer.extruder()->retract_speed() * wipe_speed);
    
        /*  Take the stored wipe path and replace first point with the current actual position
            (they might be different, for example, in case of loop clipping).  */
        Polyline wipe_path;
        wipe_path.append(gcodegen.last_pos());
        wipe_path.append(
            this->path.points.begin() + 1,
            this->path.points.end()
        );
        
        wipe_path.clip_end(wipe_path.length() - wipe_dist);
    
        // subdivide the retraction in segments
        double retracted = 0;
        Lines lines = wipe_path.lines();
        for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line) {
            double segment_length = line->length();
            /*  Reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one
                due to rounding (TODO: test and/or better math for this)  */
            double dE = length * (segment_length / wipe_dist) * 0.95;
            gcode += gcodegen.writer.set_speed(wipe_speed*60);
            gcode += gcodegen.writer.extrude_to_xy(
                gcodegen.point_to_gcode(line->b),
                -dE,
                (std::string)"wipe and retract" + (gcodegen.enable_cooling_markers ? ";_WIPE" : "")
            );
            retracted += dE;
        }
        gcodegen.writer.extruder()->retracted += retracted;
        
        // prevent wiping again on same path
        this->reset_path();
    }
    
    return gcode;
}
Example #2
0
bool
Polyline::is_straight() const
{
    /*  Check that each segment's direction is equal to the line connecting
        first point and last point. (Checking each line against the previous
        one would cause the error to accumulate.) */
    double dir = Line(this->first_point(), this->last_point()).direction();
    
    Lines lines = this->lines();
    for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line) {
        if (!line->parallel_to(dir)) return false;
    }
    return true;
}
void vavImage::ShowEdgeLine(const Lines& li)
{
	for (Lines::const_iterator it = li.begin(); it != li.end(); ++it)
	{
		int R = 255, B = 255, G = 255;
		for (Line::const_iterator it2 = it->begin(); it2 != it->end(); ++it2)
		{
			cv::Vec3b& intensity = m_Image.at<cv::Vec3b>(it2->y, it2->x);
			intensity[0] = R;
			intensity[1] = G;
			intensity[2] = B;
		}
	}
}
Example #4
0
void
BridgeDetector::unsupported_edges(double angle, Polylines* unsupported) const
{
    // get bridge edges (both contour and holes)
    Polylines bridge_edges;
    {
        Polygons pp = this->expolygon;
        bridge_edges.insert(bridge_edges.end(), pp.begin(), pp.end());  // this uses split_at_first_point()
    }

    // get unsupported edges
    Polygons grown_lower;
    offset(this->lower_slices, &grown_lower, +this->extrusion_width);
    Polylines _unsupported;
    diff(bridge_edges, grown_lower, &_unsupported);

    /*  Split into individual segments and filter out edges parallel to the bridging angle
        TODO: angle tolerance should probably be based on segment length and flow width,
        so that we build supports whenever there's a chance that at least one or two bridge
        extrusions would be anchored within such length (i.e. a slightly non-parallel bridging
        direction might still benefit from anchors if long enough) */
    double angle_tolerance = PI / 180.0 * 5.0;
    for (Polylines::const_iterator polyline = _unsupported.begin(); polyline != _unsupported.end(); ++polyline) {
        Lines lines = polyline->lines();
        for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line) {
            if (!xd::Geometry::directions_parallel(line->direction(), angle))
                unsupported->push_back(*line);
        }
    }

    /*
    if (0) {
        require "Slic3r/SVG.pm";
        Slic3r::SVG::output(
            "unsupported_" . rad2deg($angle) . ".svg",
            expolygons          => [$self->expolygon],
            green_expolygons    => $self->_anchors,
            red_expolygons      => union_ex($grown_lower),
            no_arrows           => 1,
            polylines           => \@bridge_edges,
            red_polylines       => $unsupported,
        );
    }
    */
}
Example #5
0
// This method accepts &point in print coordinates.
std::string
GCode::travel_to(const Point &point, ExtrusionRole role, std::string comment)
{    
    /*  Define the travel move as a line between current position and the taget point.
        This is expressed in print coordinates, so it will need to be translated by
        this->origin in order to get G-code coordinates.  */
    Polyline travel;
    travel.append(this->last_pos());
    travel.append(point);
        std::string gcode;
    // check whether a straight travel move would need retraction
    bool needs_retraction = this->needs_retraction(travel, role);
    std::stringstream ss;
    ss << ";needs retr 1: " << needs_retraction << "\n";
    gcode += ss.str();
    // if a retraction would be needed, try to use avoid_crossing_perimeters to plan a
    // multi-hop travel path inside the configuration space
    if (needs_retraction
        && this->config.avoid_crossing_perimeters
        && !this->avoid_crossing_perimeters.disable_once) {
        travel = this->avoid_crossing_perimeters.travel_to(*this, point);
        gcode += ";HERE!!!!!\n";
        // check again whether the new travel path still needs a retraction
        needs_retraction = this->needs_retraction(travel, role);
        std::stringstream ss;
        ss << ";needs retr 2: " << needs_retraction << "\n";
        gcode += ss.str();
        //if (needs_retraction && this->layer_index > 1) exit(0);
    }
    //needs_retraction = true; //vladi
    //if (this->first_layer) needs_retraction = false;//vladi
    // Re-allow avoid_crossing_perimeters for the next travel moves
    this->avoid_crossing_perimeters.disable_once = false;
    this->avoid_crossing_perimeters.use_external_mp_once = false;
    
    // generate G-code for the travel move
    //if (travel.lines().begin()->length() * SCALING_FACTOR > 2 && this->first_layer) needs_retraction = true;
    //std::size_t found = comment.find("infill");
    bool willDoInfill = (comment.find("infill") != std::string::npos);
    //if (comment.find("infill") != std::string::npos && this->first_layer) needs_retraction = false;
    

    if (needs_retraction) gcode += this->retract();
    
    // use G1 because we rely on paths being straight (G0 may make round paths)
    Lines lines = travel.lines();
    double path_length = 0;
    for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line) {
	    const double line_length = line->length() * SCALING_FACTOR;
	    path_length += line_length;
        std::stringstream ss1;
        ss1 << ";Will Travel: " << line_length << ", on layer height: " << this->layer->print_z <<  ", id" << this->layer->id() << "\n";
        gcode += ss1.str();
        
        if (this->first_layer && line_length > 3 && !willDoInfill) {
           if (needs_retraction) {
               gcode += this->unretract();
               gcode += this->writer.travel_to_z(this->layer->print_z, "extrude move on layer height");
           } else {
               gcode += this->writer.travel_to_z(0.1, "extrude move 333");
           }
           double fil_sq = 3.14f *1.75f*1.75f/4;
           double exr_line = 0.1f*0.4f;
           double e = exr_line *line_length/fil_sq;
           //double e_per_mm = this->writer.extruder()->e_per_mm3 * path.mm3_per_mm;
          // gcode += "G1 F6000\n";
           gcode += this->writer.extrude_to_xy(this->point_to_gcode(line->b), e, comment);
           gcode += this->writer.travel_to_z(this->layer->print_z, "return");
           lowerSpeed = true;
        } else {
            gcode += this->writer.travel_to_xy(this->point_to_gcode(line->b), comment);
        }
    }

    if (this->config.cooling)
        this->elapsed_time += path_length / this->config.get_abs_value("travel_speed");

    return gcode;
}
Example #6
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;
}
Example #7
0
bool
BridgeDetector::detect_angle()
{
    if (this->_edges.empty() || this->_anchors.empty()) return false;

    /*  Outset the bridge expolygon by half the amount we used for detecting anchors;
        we'll use this one to clip our test lines and be sure that their endpoints
        are inside the anchors and not on their contours leading to false negatives. */
    Polygons clip_area;
    offset(this->expolygon, &clip_area, +this->extrusion_width/2);

    /*  we'll now try several directions using a rudimentary visibility check:
        bridge in several directions and then sum the length of lines having both
        endpoints within anchors */

    // we test angles according to configured resolution
    std::vector<double> angles;
    for (int i = 0; i <= PI/this->resolution; ++i)
        angles.push_back(i * this->resolution);

    // we also test angles of each bridge contour
    {
        Polygons pp = this->expolygon;
        for (Polygons::const_iterator p = pp.begin(); p != pp.end(); ++p) {
            Lines lines = p->lines();
            for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line)
                angles.push_back(line->direction());
        }
    }

    /*  we also test angles of each open supporting edge
        (this finds the optimal angle for C-shaped supports) */
    for (Polylines::const_iterator edge = this->_edges.begin(); edge != this->_edges.end(); ++edge) {
        if (edge->first_point().coincides_with(edge->last_point())) continue;
        angles.push_back(Line(edge->first_point(), edge->last_point()).direction());
    }

    // remove duplicates
    double min_resolution = PI/180.0;  // 1 degree
    std::sort(angles.begin(), angles.end());
    for (size_t i = 1; i < angles.size(); ++i) {
        if (xd::Geometry::directions_parallel(angles[i], angles[i-1], min_resolution)) {
            angles.erase(angles.begin() + i);
            --i;
        }
    }
    /*  compare first value with last one and remove the greatest one (PI)
        in case they are parallel (PI, 0) */
    if (xd::Geometry::directions_parallel(angles.front(), angles.back(), min_resolution))
        angles.pop_back();

    BridgeDirectionComparator bdcomp(this->extrusion_width);
    double line_increment = this->extrusion_width;
    bool have_coverage = false;
    for (std::vector<double>::const_iterator angle = angles.begin(); angle != angles.end(); ++angle) {
        Polygons my_clip_area = clip_area;
        ExPolygons my_anchors = this->_anchors;

        // rotate everything - the center point doesn't matter
        for (Polygons::iterator it = my_clip_area.begin(); it != my_clip_area.end(); ++it)
            it->rotate(-*angle, Point(0,0));
        for (ExPolygons::iterator it = my_anchors.begin(); it != my_anchors.end(); ++it)
            it->rotate(-*angle, Point(0,0));

        // generate lines in this direction
        BoundingBox bb;
        for (ExPolygons::const_iterator it = my_anchors.begin(); it != my_anchors.end(); ++it)
            bb.merge((Points)*it);

        Lines lines;
        for (coord_t y = bb.min.y; y <= bb.max.y; y += line_increment)
            lines.push_back(Line(Point(bb.min.x, y), Point(bb.max.x, y)));

        Lines clipped_lines;
        intersection(lines, my_clip_area, &clipped_lines);

        // remove any line not having both endpoints within anchors
        for (size_t i = 0; i < clipped_lines.size(); ++i) {
            Line &line = clipped_lines[i];
            if (!xd::Geometry::contains(my_anchors, line.a)
                    || !xd::Geometry::contains(my_anchors, line.b)) {
                clipped_lines.erase(clipped_lines.begin() + i);
                --i;
            }
        }

        std::vector<double> lengths;
        double total_length = 0;
        for (Lines::const_iterator line = clipped_lines.begin(); line != clipped_lines.end(); ++line) {
            double len = line->length();
            lengths.push_back(len);
            total_length += len;
        }
        if (total_length) have_coverage = true;

        // sum length of bridged lines
        bdcomp.dir_coverage[*angle] = total_length;

        /*  The following produces more correct results in some cases and more broken in others.
            TODO: investigate, as it looks more reliable than line clipping. */
        // $directions_coverage{$angle} = sum(map $_->area, @{$self->coverage($angle)}) // 0;

        // max length of bridged lines
        bdcomp.dir_avg_length[*angle] = !lengths.empty()
                                        ? *std::max_element(lengths.begin(), lengths.end())
                                        : 0;
    }

    // if no direction produced coverage, then there's no bridge direction
    if (!have_coverage) return false;

    // sort directions by score
    std::sort(angles.begin(), angles.end(), bdcomp);

    this->angle = angles.front();
    if (this->angle >= PI) this->angle -= PI;

//    #ifdef SLIC3R_DEBUG
//    printf("  Optimal infill angle is %d degrees\n", (int)Slic3r::Geometry::rad2deg(this->angle));
//    #endif

    return true;
}