bool MergeInfillLines::mergeInfillLines(double speed, unsigned int& path_idx)
{ //Check for lots of small moves and combine them into one large line
    Point prev_middle;
    Point last_middle;
    int64_t line_width;

    if (isConvertible(path_idx, prev_middle, last_middle, line_width, false))
    {
        //   path_idx + 3 is the index of the second extrusion move to be converted in combination with the first
        {
            GCodePath& move_path = paths[path_idx];
            for(unsigned int point_idx = 0; point_idx < move_path.points.size() - 1; point_idx++)
            {
                gcode.writeMove(move_path.points[point_idx], speed, move_path.getExtrusionMM3perMM());
            }
            gcode.writeMove(prev_middle, travelConfig.getSpeed(), 0);
            GCodePath& last_path = paths[path_idx + 3];
            
            writeCompensatedMove(last_middle, speed, last_path, line_width);
        }
        
        path_idx += 2;
        extruder_plan.handleInserts(path_idx, gcode);
        for (; isConvertible(path_idx, prev_middle, last_middle, line_width, true); path_idx += 2)
        {
            extruder_plan.handleInserts(path_idx, gcode);
            GCodePath& last_path = paths[path_idx + 3];
            writeCompensatedMove(last_middle, speed, last_path, line_width);
        }
        path_idx = path_idx + 1; // means that the next path considered is the travel path after the converted extrusion path corresponding to the updated path_idx
        extruder_plan.handleInserts(path_idx, gcode);
        return true;
    }
    return false;
};
bool MergeInfillLines::isConvertible(unsigned int path_idx_first_move, Point& first_middle, Point& second_middle, int64_t& resulting_line_width, bool use_second_middle_as_first)
{
    unsigned int idx = path_idx_first_move;
    if (idx + 3 > paths.size()-1) 
    {
        return false;
    }
    if (   paths[idx+0].config != &travelConfig // must be travel
        || paths[idx+1].points.size() > 1
        || paths[idx+1].config == &travelConfig // must be extrusion
//        || paths[idx+2].points.size() > 1
        || paths[idx+2].config != &travelConfig // must be travel
        || paths[idx+3].points.size() > 1
        || paths[idx+3].config == &travelConfig // must be extrusion
        || paths[idx+1].config != paths[idx+3].config // both extrusion moves should have the same config
    )
    {
        return false;
    }
    
    int64_t line_width = paths[idx+1].config->getLineWidth();
    
    Point& a = paths[idx+0].points.back(); // first extruded line from
    Point& b = paths[idx+1].points.back(); // first extruded line to
    Point& c = paths[idx+2].points.back(); // second extruded line from
    Point& d = paths[idx+3].points.back(); // second extruded line to
    
    return isConvertible(a, b, c, d, line_width, first_middle, second_middle, resulting_line_width, use_second_middle_as_first);
}
bool MergeInfillLines::isConvertible(unsigned int path_idx_first_move, Point& first_middle, Point& second_middle, int64_t& resulting_line_width, bool use_second_middle_as_first)
{
    unsigned int idx = path_idx_first_move;
    if (idx + 3 > paths.size()-1) 
    {
        return false;
    }
    if (   paths[idx+0].config != &travelConfig // must be travel
        || paths[idx+1].points.size() > 1       // extrusion path is single line
        || paths[idx+1].config == &travelConfig // must be extrusion
//        || paths[idx+2].points.size() > 1       // travel must be direct
        || paths[idx+2].config != &travelConfig // must be travel
        || paths[idx+3].points.size() > 1       // extrusion path is single line
        || paths[idx+3].config == &travelConfig // must be extrusion
        || paths[idx+1].config != paths[idx+3].config // both extrusion moves should have the same config
    )
    {
        return false;
    }

    if (!(paths[idx+1].config->type == PrintFeatureType::Infill || paths[idx+1].config->type == PrintFeatureType::Skin))
    { // only (skin) infill lines can be merged (note that the second extrusion line config is already checked to be the same as the first in code above)
        return false;
    }

    if (paths[idx+1].space_fill_type != SpaceFillType::Lines || paths[idx+3].space_fill_type != SpaceFillType::Lines)
    { // both extrusion moves must be of lines space filling type!
        return false;
    }

    int64_t line_width = paths[idx+1].config->getLineWidth();
    
    Point& a = paths[idx+0].points.back(); // first extruded line from
    Point& b = paths[idx+1].points.back(); // first extruded line to
    Point& c = paths[idx+2].points.back(); // second extruded line from
    Point& d = paths[idx+3].points.back(); // second extruded line to
    
    return isConvertible(a, b, c, d, line_width, first_middle, second_middle, resulting_line_width, use_second_middle_as_first);
}