mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	Add the full source of BambuStudio
using version 1.0.10
This commit is contained in:
		
							parent
							
								
									30bcadab3e
								
							
						
					
					
						commit
						1555904bef
					
				
					 3771 changed files with 1251328 additions and 0 deletions
				
			
		
							
								
								
									
										4
									
								
								bbs_test_tools/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								bbs_test_tools/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
# Add individual tools as executables in separate directories
 | 
			
		||||
add_subdirectory(bbs_gcode_checker)
 | 
			
		||||
 | 
			
		||||
install(TARGETS bbs_gcode_checker RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}")
 | 
			
		||||
							
								
								
									
										6
									
								
								bbs_test_tools/bbs_gcode_checker/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								bbs_test_tools/bbs_gcode_checker/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
cmake_minimum_required (VERSION 3.8)
 | 
			
		||||
 | 
			
		||||
project ("bbs_gcode_checker")
 | 
			
		||||
 | 
			
		||||
add_executable (bbs_gcode_checker "main.cpp" "GCodeChecker.cpp" "GCodeChecker.h" )
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										602
									
								
								bbs_test_tools/bbs_gcode_checker/GCodeChecker.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										602
									
								
								bbs_test_tools/bbs_gcode_checker/GCodeChecker.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,602 @@
 | 
			
		|||
#include "GCodeChecker.h"
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <map>
 | 
			
		||||
 | 
			
		||||
namespace BambuStudio {
 | 
			
		||||
 | 
			
		||||
//BBS: only check wodth when dE is longer than this value
 | 
			
		||||
const double CHECK_WIDTH_E_THRESHOLD = 0.0025;
 | 
			
		||||
const double WIDTH_THRESHOLD = 0.012;
 | 
			
		||||
const double RADIUS_THRESHOLD = 0.005;
 | 
			
		||||
 | 
			
		||||
const double filament_diameter = 1.75;
 | 
			
		||||
const double Pi = 3.14159265358979323846;
 | 
			
		||||
 | 
			
		||||
const std::string Extrusion_Role_Tag = " FEATURE: ";
 | 
			
		||||
const std::string Width_Tag          = " LINE_WIDTH: ";
 | 
			
		||||
const std::string Wipe_Start_Tag     = " WIPE_START";
 | 
			
		||||
const std::string Wipe_End_Tag       = " WIPE_END";
 | 
			
		||||
const std::string Layer_Change_Tag   = " CHANGE_LAYER";
 | 
			
		||||
const std::string Height_Tag         = " LAYER_HEIGHT: ";
 | 
			
		||||
 | 
			
		||||
GCodeCheckResult GCodeChecker::parse_file(const std::string& path)
 | 
			
		||||
{
 | 
			
		||||
    std::ifstream file(path);
 | 
			
		||||
    if (file.fail()) {
 | 
			
		||||
        std::cout << "Failed to open file " << path << std::endl;
 | 
			
		||||
        return GCodeCheckResult::ParseFailed;
 | 
			
		||||
    }
 | 
			
		||||
    std::string line_raw;
 | 
			
		||||
    std::string line;
 | 
			
		||||
    while (std::getline(file, line_raw)) {
 | 
			
		||||
        const char *c = line_raw.c_str();
 | 
			
		||||
        c = skip_whitespaces(c);
 | 
			
		||||
        if (std::toupper(*c) == 'N')
 | 
			
		||||
            c = skip_word(c);
 | 
			
		||||
        c = skip_whitespaces(c);
 | 
			
		||||
        line = c;
 | 
			
		||||
        if (parse_line(line) != GCodeCheckResult::Success) {
 | 
			
		||||
            std::cout << "Failed to parse line " << line_raw << std::endl;
 | 
			
		||||
            return GCodeCheckResult::ParseFailed;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (m_layer_num == 0) {
 | 
			
		||||
        std::cout << "Invalid gcode file without layer change comment" << std::endl;
 | 
			
		||||
        return GCodeCheckResult::ParseFailed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return GCodeCheckResult::Success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool GCodeChecker::include_chinese(const char* str)
 | 
			
		||||
{
 | 
			
		||||
   char c;
 | 
			
		||||
   while(1)
 | 
			
		||||
   {
 | 
			
		||||
       c=*str++;
 | 
			
		||||
       if (is_end_of_line(c))
 | 
			
		||||
           break;
 | 
			
		||||
       if ((c & 0x80) && (*str & 0x80))
 | 
			
		||||
           return true;
 | 
			
		||||
   }
 | 
			
		||||
   return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GCodeCheckResult GCodeChecker::parse_line(const std::string& line)
 | 
			
		||||
{
 | 
			
		||||
    // update start position
 | 
			
		||||
    m_start_position = m_end_position;
 | 
			
		||||
 | 
			
		||||
    GCodeCheckResult ret;
 | 
			
		||||
    const char *c = skip_whitespaces(line.c_str());
 | 
			
		||||
    if (include_chinese(c)) {
 | 
			
		||||
        //chinese is forbidden
 | 
			
		||||
        return GCodeCheckResult::ParseFailed;
 | 
			
		||||
    } if (is_end_of_line(*c)) {
 | 
			
		||||
        //BBS: skip empty line
 | 
			
		||||
        return GCodeCheckResult::Success;
 | 
			
		||||
    } else if (is_comment_line(*c)) {
 | 
			
		||||
        GCodeLine gcode_line;
 | 
			
		||||
        gcode_line.m_raw = c;
 | 
			
		||||
        ret = parse_comment(gcode_line);
 | 
			
		||||
        if (ret != GCodeCheckResult::Success)
 | 
			
		||||
            return ret;
 | 
			
		||||
    } else {
 | 
			
		||||
        GCodeLine gcode_line;
 | 
			
		||||
        gcode_line.m_raw = c;
 | 
			
		||||
        ret = parse_command(gcode_line);
 | 
			
		||||
        if (ret != GCodeCheckResult::Success)
 | 
			
		||||
            return ret;
 | 
			
		||||
        ret = check_line_width(gcode_line);
 | 
			
		||||
        if (ret != GCodeCheckResult::Success)
 | 
			
		||||
            return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return GCodeCheckResult::Success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GCodeCheckResult GCodeChecker::parse_comment(GCodeLine& line)
 | 
			
		||||
{
 | 
			
		||||
    const char *c = line.m_raw.c_str();
 | 
			
		||||
    c++;
 | 
			
		||||
    std::string comment = c;
 | 
			
		||||
    // extrusion role tag
 | 
			
		||||
    if (starts_with(comment, Extrusion_Role_Tag)) {
 | 
			
		||||
        m_role = string_to_role(comment.substr(Extrusion_Role_Tag.length()));
 | 
			
		||||
    } else if (starts_with(comment, Wipe_Start_Tag)) {
 | 
			
		||||
        m_wiping = true;
 | 
			
		||||
    } else if (starts_with(comment, Wipe_End_Tag)) {
 | 
			
		||||
        m_wiping = false;
 | 
			
		||||
    } else if (starts_with(comment, Height_Tag)) {
 | 
			
		||||
        std::string str = comment.substr(Height_Tag.size());
 | 
			
		||||
        if (!parse_double_from_str(str, m_height)) {
 | 
			
		||||
            std::cout << "invalid height comment with invalid value!" << std::endl;
 | 
			
		||||
            return GCodeCheckResult::ParseFailed;
 | 
			
		||||
        }
 | 
			
		||||
    } else if (starts_with(comment, Width_Tag)) {
 | 
			
		||||
        std::string str = comment.substr(Width_Tag.size());
 | 
			
		||||
        if (!parse_double_from_str(str, m_width)) {
 | 
			
		||||
            std::cout << "invalid width comment with invalid value!" << std::endl;
 | 
			
		||||
            return GCodeCheckResult::ParseFailed;
 | 
			
		||||
        }
 | 
			
		||||
    } else if (starts_with(comment, Layer_Change_Tag)) {
 | 
			
		||||
        m_layer_num++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return GCodeCheckResult::Success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GCodeCheckResult GCodeChecker::parse_command(GCodeLine& gcode_line)
 | 
			
		||||
{
 | 
			
		||||
    const std::string cmd = gcode_line.cmd();
 | 
			
		||||
    GCodeCheckResult ret = GCodeCheckResult::Success;
 | 
			
		||||
    switch (::toupper(cmd[0])) {
 | 
			
		||||
        case 'G':
 | 
			
		||||
        {
 | 
			
		||||
            switch (::atoi(&cmd[1]))
 | 
			
		||||
            {
 | 
			
		||||
                case 0:
 | 
			
		||||
                case 1:  { ret = parse_G0_G1(gcode_line); break; }  // Move
 | 
			
		||||
                case 2:
 | 
			
		||||
                case 3:  { ret = parse_G2_G3(gcode_line); break; }  // Move
 | 
			
		||||
                case 90: { ret = parse_G90(gcode_line); break; }    // Set to Absolute Positioning
 | 
			
		||||
                case 91: { ret = parse_G91(gcode_line); break; }    // Set to Relative Positioning
 | 
			
		||||
                case 92: { ret = parse_G92(gcode_line); break; }    // Set Position
 | 
			
		||||
                default: { break; }
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case 'M':{
 | 
			
		||||
            switch (::atoi(&cmd[1]))
 | 
			
		||||
            {
 | 
			
		||||
                case 82: { ret = parse_M82(gcode_line); break; }    // Set to Absolute extrusion
 | 
			
		||||
                case 83: { ret = parse_M83(gcode_line); break; }    // Set to Relative extrusion
 | 
			
		||||
                default: { break; }
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case 'T':{
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        default: {
 | 
			
		||||
            //BBS: other g command? impossible! must be invalid
 | 
			
		||||
            ret = GCodeCheckResult::ParseFailed;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GCodeCheckResult GCodeChecker::parse_axis(GCodeLine& gcode_line)
 | 
			
		||||
{
 | 
			
		||||
    const std::string cmd = gcode_line.m_raw;
 | 
			
		||||
    const char* c = cmd.c_str();
 | 
			
		||||
    c = skip_word(c);
 | 
			
		||||
    while (! is_end_of_gcode_line(*c)) {
 | 
			
		||||
        c = skip_whitespaces(c);
 | 
			
		||||
        if (is_end_of_gcode_line(*c))
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        Axis axis = UNKNOWN_AXIS;
 | 
			
		||||
        switch (*c) {
 | 
			
		||||
        case 'X': axis = X; break;
 | 
			
		||||
        case 'Y': axis = Y; break;
 | 
			
		||||
        case 'Z': axis = Z; break;
 | 
			
		||||
        case 'E': axis = E; break;
 | 
			
		||||
        case 'F': axis = F; break;
 | 
			
		||||
        case 'I': axis = I; break;
 | 
			
		||||
        case 'J': axis = J; break;
 | 
			
		||||
        default:
 | 
			
		||||
            //BBS: invalid command which has invalid axis
 | 
			
		||||
            std::cout << "Invalid gcode because of invalid axis!" << std::endl;
 | 
			
		||||
            return GCodeCheckResult::ParseFailed;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        char   *pend = nullptr;
 | 
			
		||||
        double v = strtod(++c, &pend);
 | 
			
		||||
        if (pend != nullptr && is_end_of_word(*pend) && !isnan(v) && !isinf(v)) {
 | 
			
		||||
	        gcode_line.m_axis[int(axis)] = v;
 | 
			
		||||
            if (gcode_line.m_mask & (1 << int(axis))) {
 | 
			
		||||
                //BBS: invalid command which has duplicated axis
 | 
			
		||||
                std::cout << "Invalid gcode because of duplicated axis!" << std::endl;
 | 
			
		||||
                return GCodeCheckResult::ParseFailed;
 | 
			
		||||
            } else {
 | 
			
		||||
                gcode_line.m_mask |= 1 << int(axis);
 | 
			
		||||
            }
 | 
			
		||||
            if (c == pend) {
 | 
			
		||||
                //BBS: invalid command which has invalid axis value
 | 
			
		||||
                std::cout << "Invalid gcode because of invalid axis value!" << std::endl;
 | 
			
		||||
                return GCodeCheckResult::ParseFailed;
 | 
			
		||||
            }
 | 
			
		||||
            c = pend;
 | 
			
		||||
        } else {
 | 
			
		||||
            //BBS: invalid command for invalid axis value
 | 
			
		||||
            std::cout << "Invalid gcode because of invalid axis value!" << std::endl;
 | 
			
		||||
            return GCodeCheckResult::ParseFailed;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return GCodeCheckResult::Success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GCodeCheckResult GCodeChecker::parse_G0_G1(GCodeLine& gcode_line)
 | 
			
		||||
{
 | 
			
		||||
    if (parse_axis(gcode_line) != GCodeCheckResult::Success)
 | 
			
		||||
        return GCodeCheckResult::ParseFailed;
 | 
			
		||||
 | 
			
		||||
    //BBS: invalid G1 command which has no axis or invalid axis
 | 
			
		||||
    if ((!gcode_line.m_mask) ||
 | 
			
		||||
        gcode_line.has(I) ||
 | 
			
		||||
        gcode_line.has(J)) {
 | 
			
		||||
        std::cout << "Invalid G0_G1 gcode because of no axis or invalid axis!" << std::endl;
 | 
			
		||||
        return GCodeCheckResult::ParseFailed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //BBS: invalid G1 command which has zero speed
 | 
			
		||||
    if (gcode_line.has(F) && gcode_line.get(F) == 0.0) {
 | 
			
		||||
        std::cout << "Invalid G0_G1 gcode because has F axis but 0 speed!" << std::endl;
 | 
			
		||||
        return GCodeCheckResult::ParseFailed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return GCodeCheckResult::Success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GCodeCheckResult GCodeChecker::parse_G2_G3(GCodeLine& gcode_line)
 | 
			
		||||
{
 | 
			
		||||
    if (parse_axis(gcode_line) != GCodeCheckResult::Success)
 | 
			
		||||
        return GCodeCheckResult::ParseFailed;
 | 
			
		||||
 | 
			
		||||
    //BBS: invalid G2_G3 command which has no axis or Z axis
 | 
			
		||||
    if (!gcode_line.m_mask) {
 | 
			
		||||
        std::cout << "Invalid G2_G3 gcode because of no axis or has Z axis!" << std::endl;
 | 
			
		||||
        return GCodeCheckResult::ParseFailed;
 | 
			
		||||
    }
 | 
			
		||||
    //BBS: invalid G2_G3 command which has zero speed
 | 
			
		||||
    if (gcode_line.has(F) && gcode_line.get(F) == 0.0) {
 | 
			
		||||
        std::cout << "Invalid G2_G3 gcode because has F axis but 0 speed!" << std::endl;
 | 
			
		||||
        return GCodeCheckResult::ParseFailed;
 | 
			
		||||
    }
 | 
			
		||||
    //BBS: invalid G2_G3 command which has no I and J axis
 | 
			
		||||
    if (!gcode_line.has(I) &&
 | 
			
		||||
        !gcode_line.has(J)) {
 | 
			
		||||
        std::cout << "Invalid G2_G3 gcode because of no I and J axis at same time!" << std::endl;
 | 
			
		||||
        return GCodeCheckResult::ParseFailed;
 | 
			
		||||
    }
 | 
			
		||||
    //BBS: invalid G2_G3 command which has no X and Y axis at same time
 | 
			
		||||
    if (!gcode_line.has(X) &&
 | 
			
		||||
        !gcode_line.has(Y)) {
 | 
			
		||||
        if (!gcode_line.has(X) || !gcode_line.has(P) || (int)gcode_line.get(P) != 1) {
 | 
			
		||||
            std::cout << "Invalid G2_G3 gcode because of no X and Y axis at same time!" << std::endl;
 | 
			
		||||
            return GCodeCheckResult::ParseFailed;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return GCodeCheckResult::Success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GCodeCheckResult GCodeChecker::parse_G90(const GCodeLine& gcode_line)
 | 
			
		||||
{
 | 
			
		||||
    const char* c = gcode_line.m_raw.c_str();
 | 
			
		||||
    //BBS: G90 is single command with no argument
 | 
			
		||||
    if (!is_single_gcode_word(c)) {
 | 
			
		||||
        std::cout << "Invalid G90 gcode with invalid end!" << std::endl;
 | 
			
		||||
        return GCodeCheckResult::ParseFailed;
 | 
			
		||||
    }
 | 
			
		||||
    m_global_positioning_type = EPositioningType::Absolute;
 | 
			
		||||
    return GCodeCheckResult::Success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GCodeCheckResult GCodeChecker::parse_G91(const GCodeLine& gcode_line)
 | 
			
		||||
{
 | 
			
		||||
    const char* c = gcode_line.m_raw.c_str();
 | 
			
		||||
    //BBS: G91 is single command with no argument
 | 
			
		||||
    if (!is_single_gcode_word(c)) {
 | 
			
		||||
        std::cout << "Invalid G91 gcode with invalid end!" << std::endl;
 | 
			
		||||
        return GCodeCheckResult::ParseFailed;
 | 
			
		||||
    }
 | 
			
		||||
    m_global_positioning_type = EPositioningType::Relative;
 | 
			
		||||
    return GCodeCheckResult::Success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GCodeCheckResult GCodeChecker::parse_G92(GCodeLine& gcode_line)
 | 
			
		||||
{
 | 
			
		||||
    if (parse_axis(gcode_line) != GCodeCheckResult::Success)
 | 
			
		||||
        return GCodeCheckResult::ParseFailed;
 | 
			
		||||
 | 
			
		||||
    //BBS: invalid G92 command which has no axis or invalid axis
 | 
			
		||||
    if (!gcode_line.m_mask ||
 | 
			
		||||
        gcode_line.has(F) ||
 | 
			
		||||
        gcode_line.has(I) ||
 | 
			
		||||
        gcode_line.has(J)) {
 | 
			
		||||
        std::cout << "Invalid G2_G3 gcode because of no axis or invalid axis!" << std::endl;
 | 
			
		||||
        return GCodeCheckResult::ParseFailed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (gcode_line.has(X))
 | 
			
		||||
        m_origin[X] = m_end_position[X] - gcode_line.get(X);
 | 
			
		||||
 | 
			
		||||
    if (gcode_line.has(Y))
 | 
			
		||||
        m_origin[Y] = m_end_position[Y] - gcode_line.get(Y);
 | 
			
		||||
 | 
			
		||||
    if (gcode_line.has(Z))
 | 
			
		||||
        m_origin[Z] = m_end_position[Z] - gcode_line.get(Z);
 | 
			
		||||
 | 
			
		||||
    if (gcode_line.has(E))
 | 
			
		||||
        m_end_position[E] = gcode_line.get(E);
 | 
			
		||||
 | 
			
		||||
    for (unsigned char a = X; a <= E; ++a) {
 | 
			
		||||
        m_origin[a] = m_end_position[a];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return GCodeCheckResult::Success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GCodeCheckResult GCodeChecker::parse_M82(const GCodeLine& gcode_line)
 | 
			
		||||
{
 | 
			
		||||
    const char* c = gcode_line.m_raw.c_str();
 | 
			
		||||
    //BBS: M82 is single command with no argument
 | 
			
		||||
    if (!is_single_gcode_word(c)) {
 | 
			
		||||
        std::cout << "Invalid M82 gcode with invalid end!" << std::endl;
 | 
			
		||||
        return GCodeCheckResult::ParseFailed;
 | 
			
		||||
    }
 | 
			
		||||
    m_e_local_positioning_type = EPositioningType::Absolute;
 | 
			
		||||
    return GCodeCheckResult::Success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GCodeCheckResult GCodeChecker::parse_M83(const GCodeLine& gcode_line)
 | 
			
		||||
{
 | 
			
		||||
    const char* c = gcode_line.m_raw.c_str();
 | 
			
		||||
    //BBS: M83 is single command with no argument
 | 
			
		||||
    if (!is_single_gcode_word(c)) {
 | 
			
		||||
        std::cout << "Invalid M83 gcode with invalid end!" << std::endl;
 | 
			
		||||
        return GCodeCheckResult::ParseFailed;
 | 
			
		||||
    }
 | 
			
		||||
    m_e_local_positioning_type = EPositioningType::Relative;
 | 
			
		||||
    return GCodeCheckResult::Success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double GCodeChecker::calculate_G1_width(const std::array<double, 3>& source,
 | 
			
		||||
                                       const std::array<double, 3>& target,
 | 
			
		||||
                                       double e, double height, bool is_bridge) const
 | 
			
		||||
{
 | 
			
		||||
    double volume = e * Pi * (filament_diameter/2.0f) * (filament_diameter/2.0f);
 | 
			
		||||
    std::array<double, 3> delta = { target[0] - source[0],
 | 
			
		||||
                                   target[1] - source[1],
 | 
			
		||||
                                   target[2] - source[2] };
 | 
			
		||||
    double length = sqrt(delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]);
 | 
			
		||||
    double mm3_per_mm = volume / length;
 | 
			
		||||
    return is_bridge? 2 * sqrt(mm3_per_mm/Pi) :
 | 
			
		||||
           (mm3_per_mm / height) + height * (1 - 0.25 * Pi);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double GCodeChecker::calculate_G2_G3_width(const std::array<double, 2>& source,
 | 
			
		||||
                                          const std::array<double, 2>& target,
 | 
			
		||||
                                          const std::array<double, 2>& center,
 | 
			
		||||
                                          bool is_ccw, double e, double height,
 | 
			
		||||
                                          bool is_bridge) const
 | 
			
		||||
{
 | 
			
		||||
    std::array<double, 2> v1 = { source[0] - center[0], source[1] - center[1] };
 | 
			
		||||
    std::array<double, 2> v2 = { target[0] - center[0], target[1] - center[1] };
 | 
			
		||||
 | 
			
		||||
    double dot = v1[0] * v2[0] + v1[1] * v2[1];
 | 
			
		||||
    double cross = v1[0] * v2[1] - v1[1] * v2[0];
 | 
			
		||||
    double radian = atan2(cross, dot);
 | 
			
		||||
    radian = is_ccw ?
 | 
			
		||||
        (radian < 0 ? 2 * Pi + radian : radian) :
 | 
			
		||||
        (radian < 0 ? -radian : 2 * Pi - radian);
 | 
			
		||||
    double radius = sqrt(v1[0] * v1[0] + v1[1] * v1[1]);
 | 
			
		||||
    double length = radius * radian;
 | 
			
		||||
    double volume = e * Pi * (filament_diameter/2) * (filament_diameter/2);
 | 
			
		||||
    double mm3_per_mm = volume / length;
 | 
			
		||||
    return is_bridge? 2 * sqrt(mm3_per_mm/Pi) :
 | 
			
		||||
           (mm3_per_mm / height) + height * (1 - 0.25 * Pi);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GCodeCheckResult GCodeChecker::check_line_width(const GCodeLine& gcode_line)
 | 
			
		||||
{
 | 
			
		||||
    //BBS: don't need to check extrusion before first layer
 | 
			
		||||
    if (m_layer_num <= 0) {
 | 
			
		||||
        return GCodeCheckResult::Success;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    GCodeCheckResult ret = GCodeCheckResult::Success;
 | 
			
		||||
    //BBS: only need to handle G0 G1 G2 G3
 | 
			
		||||
    const std::string cmd = gcode_line.cmd();
 | 
			
		||||
    int cmd_id = ::atoi(&cmd[1]);
 | 
			
		||||
    if (::toupper(cmd[0]) == 'G')
 | 
			
		||||
        switch (::atoi(&cmd[1]))
 | 
			
		||||
        {
 | 
			
		||||
            case 0:
 | 
			
		||||
            case 1:  { ret = check_G0_G1_width(gcode_line); break; }
 | 
			
		||||
            case 2:
 | 
			
		||||
            case 3:  { ret = check_G2_G3_width(gcode_line); break; }
 | 
			
		||||
            default: { break; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GCodeCheckResult GCodeChecker::check_G0_G1_width(const GCodeLine& line)
 | 
			
		||||
{
 | 
			
		||||
    auto absolute_position = [this](Axis axis, const GCodeLine& lineG1) {
 | 
			
		||||
        bool is_relative = (m_global_positioning_type == EPositioningType::Relative);
 | 
			
		||||
        if (axis == E)
 | 
			
		||||
            is_relative |= (m_e_local_positioning_type == EPositioningType::Relative);
 | 
			
		||||
 | 
			
		||||
        if (lineG1.has(Axis(axis))) {
 | 
			
		||||
            double ret = lineG1.get(Axis(axis));
 | 
			
		||||
            return is_relative ? m_start_position[axis] + ret : m_origin[axis] + ret;
 | 
			
		||||
        } else
 | 
			
		||||
            return m_start_position[axis];
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    auto move_type = [this](const std::array<double, 4>& delta_pos) {
 | 
			
		||||
        EMoveType type = EMoveType::Noop;
 | 
			
		||||
 | 
			
		||||
        if (m_wiping)
 | 
			
		||||
            type = EMoveType::Wipe;
 | 
			
		||||
        else if (delta_pos[E] < 0.0f)
 | 
			
		||||
            type = (delta_pos[X] != 0.0f || delta_pos[Y] != 0.0f || delta_pos[Z] != 0.0f) ? EMoveType::Travel : EMoveType::Retract;
 | 
			
		||||
        else if (delta_pos[E] > 0.0f) {
 | 
			
		||||
            if (delta_pos[X] == 0.0f && delta_pos[Y] == 0.0f)
 | 
			
		||||
                type = (delta_pos[Z] == 0.0f) ? EMoveType::Unretract : EMoveType::Travel;
 | 
			
		||||
            else if (delta_pos[X] != 0.0f || delta_pos[Y] != 0.0f)
 | 
			
		||||
                type = EMoveType::Extrude;
 | 
			
		||||
        } 
 | 
			
		||||
        else if (delta_pos[X] != 0.0f || delta_pos[Y] != 0.0f || delta_pos[Z] != 0.0f)
 | 
			
		||||
            type = EMoveType::Travel;
 | 
			
		||||
 | 
			
		||||
        return type;
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    for (unsigned char a = X; a <= E; ++a) {
 | 
			
		||||
        m_end_position[a] = absolute_position((Axis)a, line);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // calculates movement deltas
 | 
			
		||||
    std::array<double, 4> delta_pos;
 | 
			
		||||
    for (unsigned char a = X; a <= E; ++a)
 | 
			
		||||
        delta_pos[a] = m_end_position[a] - m_start_position[a];
 | 
			
		||||
 | 
			
		||||
    // Todo: currently, for precision, there alwasy has possible to generate
 | 
			
		||||
    // such gcode because of decimal truncation
 | 
			
		||||
    /*if (line.has(Axis(E)) && delta_pos[E] == 0.0 && !m_wiping) {
 | 
			
		||||
        std::cout << "Invalid GCode because has E axis but 0 extrusion" << std::endl;
 | 
			
		||||
        return GCodeCheckResult::CheckFailed;
 | 
			
		||||
    }*/
 | 
			
		||||
 | 
			
		||||
    EMoveType type = move_type(delta_pos);
 | 
			
		||||
    if (type == EMoveType::Extrude && m_end_position[Z] == 0.0f)
 | 
			
		||||
        type = EMoveType::Travel;
 | 
			
		||||
 | 
			
		||||
    //BBS: calculate line width and compare.
 | 
			
		||||
    //Don't need to check gap fill which has verious width
 | 
			
		||||
    if (type == EMoveType::Extrude &&
 | 
			
		||||
        m_role != erGapFill &&
 | 
			
		||||
        delta_pos[E] > CHECK_WIDTH_E_THRESHOLD) {
 | 
			
		||||
        std::array<double, 3> source = { m_start_position[X], m_start_position[Y], m_start_position[Z] };
 | 
			
		||||
        std::array<double, 3> target = { m_end_position[X], m_end_position[Y], m_end_position[Z] };
 | 
			
		||||
 | 
			
		||||
        bool is_bridge = m_role == erOverhangPerimeter || m_role == erBridgeInfill;
 | 
			
		||||
        double width_real = calculate_G1_width(source, target, delta_pos[E], m_height, is_bridge);
 | 
			
		||||
        if (fabs(width_real - m_width) > WIDTH_THRESHOLD) {
 | 
			
		||||
            std::cout << "Invalid G0_G1 because has abnormal line width." << std::endl;
 | 
			
		||||
            std::cout << "Width: " << m_width << " Width_real: " << width_real <<  std::endl;
 | 
			
		||||
            return GCodeCheckResult::CheckFailed;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return GCodeCheckResult::Success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GCodeCheckResult GCodeChecker::check_G2_G3_width(const GCodeLine& line)
 | 
			
		||||
{
 | 
			
		||||
    auto absolute_position = [this](Axis axis, const GCodeLine& lineG2_3) {
 | 
			
		||||
        bool is_relative = (m_global_positioning_type == EPositioningType::Relative);
 | 
			
		||||
        if (axis == E)
 | 
			
		||||
            is_relative |= (m_e_local_positioning_type == EPositioningType::Relative);
 | 
			
		||||
 | 
			
		||||
        if (lineG2_3.has(Axis(axis))) {
 | 
			
		||||
            double ret = lineG2_3.get(Axis(axis));
 | 
			
		||||
            if (axis == I)
 | 
			
		||||
                return m_start_position[X] + ret;
 | 
			
		||||
            else if (axis == J)
 | 
			
		||||
                return m_start_position[Y] + ret;
 | 
			
		||||
            else
 | 
			
		||||
                return is_relative ? m_start_position[axis] + ret : m_origin[axis] + ret;
 | 
			
		||||
        } else {
 | 
			
		||||
            if (axis == I)
 | 
			
		||||
                return m_start_position[X];
 | 
			
		||||
            else if (axis == J)
 | 
			
		||||
                return m_start_position[Y];
 | 
			
		||||
            else
 | 
			
		||||
                return m_start_position[axis];
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
     auto move_type = [this](const double& delta_E) {
 | 
			
		||||
        EMoveType type = EMoveType::Noop;
 | 
			
		||||
 | 
			
		||||
        if (m_wiping)
 | 
			
		||||
            type = EMoveType::Wipe;
 | 
			
		||||
        else if (delta_E < 0.0f || delta_E == 0.0f)
 | 
			
		||||
            type = EMoveType::Travel;
 | 
			
		||||
        else
 | 
			
		||||
            type = EMoveType::Extrude;
 | 
			
		||||
 | 
			
		||||
        return type;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    for (unsigned char a = X; a <= E; ++a) {
 | 
			
		||||
        m_end_position[a] = absolute_position((Axis)a, line);
 | 
			
		||||
    }
 | 
			
		||||
    std::array<double, 2> source = { m_start_position[X], m_start_position[Y] };
 | 
			
		||||
    std::array<double, 2> target = { m_end_position[X], m_end_position[Y] };
 | 
			
		||||
    std::array<double, 2> center = { absolute_position(I, line),absolute_position(J, line) };
 | 
			
		||||
    const std::string& cmd = line.cmd();
 | 
			
		||||
    bool is_ccw = (::atoi(&cmd[1]) == 2) ? false : true;
 | 
			
		||||
    double delta_e = m_end_position[E] - m_start_position[E];
 | 
			
		||||
    EMoveType type = move_type(delta_e);
 | 
			
		||||
 | 
			
		||||
    //BBS: judge whether is normal arc by radius
 | 
			
		||||
    double radius1 = sqrt(pow((source[0] - center[0]), 2) + pow((source[1] - center[1]), 2));
 | 
			
		||||
    double radius2 = sqrt(pow((target[0] - center[0]), 2) + pow((target[1] - center[1]), 2));
 | 
			
		||||
    if (fabs(radius2 - radius1) > RADIUS_THRESHOLD) {
 | 
			
		||||
        std::cout << "Invalid G2_G3 because of abnormal radius." << std::endl;
 | 
			
		||||
        std::cout << "radius1: " << radius1 << " radius2: " << radius2 <<  std::endl;
 | 
			
		||||
        return GCodeCheckResult::CheckFailed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //BBS: calculate line width and compare
 | 
			
		||||
    //Don't need to check gap fill which has verious width
 | 
			
		||||
    if (type == EMoveType::Extrude &&
 | 
			
		||||
        m_role != erGapFill &&
 | 
			
		||||
        delta_e > CHECK_WIDTH_E_THRESHOLD) {
 | 
			
		||||
        bool is_bridge = m_role == erOverhangPerimeter || m_role == erBridgeInfill;
 | 
			
		||||
        double width_real = calculate_G2_G3_width(source, target, center, is_ccw, delta_e, m_height, is_bridge);
 | 
			
		||||
        if (fabs(width_real - m_width) > WIDTH_THRESHOLD) {
 | 
			
		||||
            std::cout << "Invalid G2_G3 because has abnormal line width." << std::endl;
 | 
			
		||||
            std::cout << "Width: " << m_width << " Width_real: " << width_real <<  std::endl;
 | 
			
		||||
            return GCodeCheckResult::CheckFailed;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return GCodeCheckResult::Success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const std::map<std::string, ExtrusionRole> string_to_role_map = {
 | 
			
		||||
    { "Inner wall",                 erPerimeter },
 | 
			
		||||
    { "Outer wall",                 erExternalPerimeter },
 | 
			
		||||
    { "Overhang wall",              erOverhangPerimeter },
 | 
			
		||||
    { "Sparse infill",              erInternalInfill },
 | 
			
		||||
    { "Internal solid infill",      erSolidInfill },
 | 
			
		||||
    { "Top surface",                erTopSolidInfill },
 | 
			
		||||
    { "Bottom surface",             erBottomSurface },
 | 
			
		||||
    { "Ironing",                    erIroning },
 | 
			
		||||
    { "Bridge",                     erBridgeInfill },
 | 
			
		||||
    { "Gap infill",                 erGapFill },
 | 
			
		||||
    { "Skirt",                      erSkirt },
 | 
			
		||||
    { "Brim",                       erBrim },
 | 
			
		||||
    { "Support",                    erSupportMaterial },
 | 
			
		||||
    { "Support interface",          erSupportMaterialInterface },
 | 
			
		||||
    { "Support transition",         erSupportTransition },
 | 
			
		||||
    { "Prime tower",                erWipeTower },
 | 
			
		||||
    { "Custom",                     erCustom },
 | 
			
		||||
    { "Mixed",                      erMixed }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ExtrusionRole GCodeChecker::string_to_role(const std::string &role)
 | 
			
		||||
{
 | 
			
		||||
    for (auto it = string_to_role_map.begin(); it != string_to_role_map.end(); it++) {
 | 
			
		||||
        if (role == it->first)
 | 
			
		||||
            return it->second;
 | 
			
		||||
    }
 | 
			
		||||
    return erNone;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										181
									
								
								bbs_test_tools/bbs_gcode_checker/GCodeChecker.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								bbs_test_tools/bbs_gcode_checker/GCodeChecker.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,181 @@
 | 
			
		|||
#ifndef _GCodeChecker_H_
 | 
			
		||||
#define _GCodeChecker_H_
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
namespace BambuStudio {
 | 
			
		||||
 | 
			
		||||
enum class GCodeCheckResult : unsigned char
 | 
			
		||||
{
 | 
			
		||||
    Success,
 | 
			
		||||
    ParseFailed,
 | 
			
		||||
    CheckFailed,
 | 
			
		||||
    Count
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class EMoveType : unsigned char
 | 
			
		||||
{
 | 
			
		||||
    Noop,
 | 
			
		||||
    Retract,
 | 
			
		||||
    Unretract,
 | 
			
		||||
    Tool_change,
 | 
			
		||||
    Color_change,
 | 
			
		||||
    Pause_Print,
 | 
			
		||||
    Custom_GCode,
 | 
			
		||||
    Travel,
 | 
			
		||||
    Wipe,
 | 
			
		||||
    Extrude,
 | 
			
		||||
    Count
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum Axis {
 | 
			
		||||
    X=0,
 | 
			
		||||
    Y,
 | 
			
		||||
    Z,
 | 
			
		||||
    E,
 | 
			
		||||
    F,
 | 
			
		||||
    I,
 | 
			
		||||
    J,
 | 
			
		||||
    P,
 | 
			
		||||
    NUM_AXES,
 | 
			
		||||
    UNKNOWN_AXIS = NUM_AXES,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum ExtrusionRole : uint8_t {
 | 
			
		||||
    erNone,
 | 
			
		||||
    erPerimeter,
 | 
			
		||||
    erExternalPerimeter,
 | 
			
		||||
    erOverhangPerimeter,
 | 
			
		||||
    erInternalInfill,
 | 
			
		||||
    erSolidInfill,
 | 
			
		||||
    erTopSolidInfill,
 | 
			
		||||
    erBottomSurface,
 | 
			
		||||
    erIroning,
 | 
			
		||||
    erBridgeInfill,
 | 
			
		||||
    erGapFill,
 | 
			
		||||
    erSkirt,
 | 
			
		||||
    erBrim,
 | 
			
		||||
    erSupportMaterial,
 | 
			
		||||
    erSupportMaterialInterface,
 | 
			
		||||
    erSupportTransition,
 | 
			
		||||
    erWipeTower,
 | 
			
		||||
    erCustom,
 | 
			
		||||
    // Extrusion role for a collection with multiple extrusion roles.
 | 
			
		||||
    erMixed,
 | 
			
		||||
    erCount
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class GCodeChecker {
 | 
			
		||||
public:
 | 
			
		||||
    class GCodeLine {
 | 
			
		||||
    public:
 | 
			
		||||
        GCodeLine() {}
 | 
			
		||||
        const std::string cmd() const {
 | 
			
		||||
            const char *cmd = GCodeChecker::skip_whitespaces(m_raw.c_str());
 | 
			
		||||
            return std::string(cmd, GCodeChecker::skip_word(cmd) - cmd);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bool has(Axis axis) const { return (m_mask & (1 << int(axis))) != 0;  }
 | 
			
		||||
        double get(Axis axis) const { return m_axis[int(axis)]; }
 | 
			
		||||
 | 
			
		||||
        std::string   m_raw;
 | 
			
		||||
        double        m_axis[NUM_AXES] = { 0.0f };
 | 
			
		||||
        uint32_t      m_mask = 0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    enum class EPositioningType : unsigned char
 | 
			
		||||
    {
 | 
			
		||||
        Absolute,
 | 
			
		||||
        Relative
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    GCodeChecker() {}
 | 
			
		||||
    GCodeCheckResult parse_file(const std::string& path);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    bool include_chinese(const char* str);
 | 
			
		||||
    GCodeCheckResult parse_line(const std::string& line);
 | 
			
		||||
 | 
			
		||||
    GCodeCheckResult parse_command(GCodeLine& gcode_line);
 | 
			
		||||
    GCodeCheckResult parse_axis(GCodeLine& gcode_line);
 | 
			
		||||
    GCodeCheckResult parse_G0_G1(GCodeLine& gcode_line);
 | 
			
		||||
    GCodeCheckResult parse_G2_G3(GCodeLine& gcode_line);
 | 
			
		||||
    GCodeCheckResult parse_G90(const GCodeLine& gcode_line);
 | 
			
		||||
    GCodeCheckResult parse_G91(const GCodeLine& gcode_line);
 | 
			
		||||
    GCodeCheckResult parse_G92(GCodeLine& gcode_line);
 | 
			
		||||
    GCodeCheckResult parse_M82(const GCodeLine& gcode_line);
 | 
			
		||||
    GCodeCheckResult parse_M83(const GCodeLine& gcode_line);
 | 
			
		||||
 | 
			
		||||
    GCodeCheckResult parse_comment(GCodeLine& gcode_line);
 | 
			
		||||
 | 
			
		||||
    GCodeCheckResult check_line_width(const GCodeLine& gcode_line);
 | 
			
		||||
    GCodeCheckResult check_G0_G1_width(const GCodeLine& gcode_line);
 | 
			
		||||
    GCodeCheckResult check_G2_G3_width(const GCodeLine& gcode_line);
 | 
			
		||||
 | 
			
		||||
    double calculate_G1_width(const std::array<double, 3>& source,
 | 
			
		||||
                             const std::array<double, 3>& target,
 | 
			
		||||
                             double e, double height, bool is_bridge) const;
 | 
			
		||||
    double calculate_G2_G3_width(const std::array<double, 2>& source,
 | 
			
		||||
                                const std::array<double, 2>& target,
 | 
			
		||||
                                const std::array<double, 2>& center,
 | 
			
		||||
                                bool is_ccw, double e, double height, bool is_bridge) const;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    static bool is_whitespace(char c) { return c == ' ' || c == '\t'; }
 | 
			
		||||
    static bool is_end_of_line(char c) { return c == '\r' || c == '\n' || c == 0; }
 | 
			
		||||
    static bool is_comment_line(char c) { return c == ';'; }
 | 
			
		||||
    static bool is_end_of_gcode_line(char c) { return is_comment_line(c) || is_end_of_line(c); }
 | 
			
		||||
    static bool is_end_of_word(char c) { return is_whitespace(c) || is_end_of_gcode_line(c); }
 | 
			
		||||
    static const char*  skip_word(const char *c) { 
 | 
			
		||||
        for (; ! is_end_of_word(*c); ++ c)
 | 
			
		||||
            ; // silence -Wempty-body
 | 
			
		||||
        return c;
 | 
			
		||||
    }
 | 
			
		||||
    static const char*  skip_whitespaces(const char *c) { 
 | 
			
		||||
        for (; is_whitespace(*c); ++ c)
 | 
			
		||||
            ; // silence -Wempty-body
 | 
			
		||||
        return c;
 | 
			
		||||
    }
 | 
			
		||||
    static bool is_single_gcode_word(const char* c) {
 | 
			
		||||
        c = skip_word(c);
 | 
			
		||||
        c = skip_whitespaces(c);
 | 
			
		||||
        return is_end_of_gcode_line(*c);
 | 
			
		||||
    }
 | 
			
		||||
    static bool starts_with(const std::string &comment, const std::string &tag) {
 | 
			
		||||
        size_t tag_len = tag.size();
 | 
			
		||||
        return comment.size() >= tag_len && comment.substr(0, tag_len) == tag;
 | 
			
		||||
    }
 | 
			
		||||
    static ExtrusionRole string_to_role(const std::string& role);
 | 
			
		||||
    //BBS: Returns true if the number was parsed correctly into out and the number spanned the whole input string.
 | 
			
		||||
    static bool parse_double_from_str(const std::string& input, double& out) {
 | 
			
		||||
        size_t read = 0;
 | 
			
		||||
        try {
 | 
			
		||||
            out = std::stod(input, &read);
 | 
			
		||||
            return input.size() == read;
 | 
			
		||||
        } catch (...) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    EPositioningType m_global_positioning_type = EPositioningType::Absolute;
 | 
			
		||||
    EPositioningType m_e_local_positioning_type = EPositioningType::Absolute;
 | 
			
		||||
 | 
			
		||||
    std::array<double, 4> m_start_position = { 0.0, 0.0, 0.0, 0.0 };
 | 
			
		||||
    std::array<double, 4> m_end_position = { 0.0, 0.0, 0.0, 0.0 };
 | 
			
		||||
    std::array<double, 4> m_origin = { 0.0, 0.0, 0.0, 0.0 };
 | 
			
		||||
 | 
			
		||||
    //BBS: use these value to save information from comment
 | 
			
		||||
    ExtrusionRole m_role = erNone;
 | 
			
		||||
    bool m_wiping = false;
 | 
			
		||||
    int m_layer_num = 0;
 | 
			
		||||
    double m_height = 0.0;
 | 
			
		||||
    double m_width = 0.0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										24
									
								
								bbs_test_tools/bbs_gcode_checker/main.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								bbs_test_tools/bbs_gcode_checker/main.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
#include "GCodeChecker.h"
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
using namespace BambuStudio;
 | 
			
		||||
 | 
			
		||||
int main(int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
    if (argc != 2) {
 | 
			
		||||
        cout << "Invalid input arguments" << endl;
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    string path(argv[1]);
 | 
			
		||||
    cout << "Start to check file " << path << endl;
 | 
			
		||||
    GCodeChecker checker;
 | 
			
		||||
 | 
			
		||||
    //BBS: parse and check whether has invalid gcode
 | 
			
		||||
    if (checker.parse_file(path) != GCodeCheckResult::Success) {
 | 
			
		||||
        cout << "Failed to parse and check file " << path << endl;
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    cout << "Success to parse and check file" << path << endl;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue