BlinkenArea - GitList
Repositories
Blog
Wiki
dxfngc
Code
Commits
Branches
Tags
Search
Tree:
3f2ac59
Branches
Tags
master
dxfngc
src
cmdparser.cpp
add support for cutting a layer path-by-path (i.e. each path all the way down, then next path)
Stefan Schuermans
commited
3f2ac59
at 2013-04-22 20:33:49
cmdparser.cpp
Blame
History
Raw
/* drawing (DXF) to G-code (NGC) converter * Copyright 2013 Stefan Schuermans <stefan@schuermans.info> * Copyleft: CC-BY-SA http://creativecommons.org/licenses/by-sa/3.0/ */ #include <fstream> #include <iostream> #include <math.h> #include <sstream> #include <string> #include "cmdparser.h" #include "drawing.h" #include "filename.h" #include "gcode.h" #include "polygons.h" #include "settings.h" /** * @brief get layer by name from stream * @param[in] strm stream to read layer name from * @param[out] name layer name from stream * @param[out] layer layer indicated by name from stream * @return if layer could be found */ bool CmdParser::getLayer(std::istream &strm, std::string &name, const Layer *&layer) const { // get layer name argument strm >> name; if (strm.fail()) { std::cerr << "missing layer name" << std::endl; return false; } // get layer Drawing::Layers::const_iterator itLayer = mDrawing.mLayers.find(name); if (itLayer == mDrawing.mLayers.end()) { std::cerr << "layer \"" << name << "\" not found" << std::endl; return false; } layer = &itLayer->second; return true; } /** * @brief get layer by name from stream and convert to polygons * @param[in] strm stream to read layer name from * @param[out] name layer name from stream * @param[out] layer layer indicated by name from stream * @param[in,out] polys polygons created from layer * @return if layer could be found and converted to polygons */ bool CmdParser::getLayerPolys(std::istream &strm, std::string &name, const Layer *&layer, Polygons &polys) const { // get layer if (!getLayer(strm, name, layer)) return false; // convert layer to polygons if (!polys.loadLayer(*layer, mSettings.precision)) { std::cerr << "cannot convert layer \"" << name << "\" to polygons" << std::endl; return false; } return true; } /** * @brief process cmd command * @param[in] strm stream to read command arguments from * @return if processing command was successful */ bool CmdParser::procCmd_cmd(std::istream &strm) { // skip whitespace and use rest of line as custom command strm >> std::ws; std::string cmd; getline(strm, cmd); // add custom command to G-code mGCode.appendCustom(cmd); return true; } /** * @brief process cut command * @param[in] strm stream to read command arguments from * @return if processing command was successful */ bool CmdParser::procCmd_cut(std::istream &strm) { // get layer from arguments std::string layerName; const Layer *layer; if (!getLayer(strm, layerName, layer)) return false; // convert layer to G-code layer->toGCode(mSettings, mGCode); return true; } /** * @brief process cut_inside command * @param[in] strm stream to read command arguments from * @return if processing command was successful */ bool CmdParser::procCmd_cut_inside(std::istream &strm) { // get layer from arguments and convert to polygons std::string layerName; const Layer *layer; Polygons polys; if (!getLayerPolys(strm, layerName, layer, polys)) return false; // inner offset polygons Polygons newPolys; if (!polys.createInnerOffset(mSettings.tool_diameter * 0.5, newPolys)) { std::cerr << "creating inner offset polygons failed" << std::endl; return false; } // convert polygons back to layer (containing paths) Layer newLayer; newPolys.writeToLayer(newLayer); newLayer.improvePaths(mSettings.precision); // convert layer to G-code newLayer.toGCode(mSettings, mGCode); return true; } /** * @brief process cut_outside command * @param[in] strm stream to read command arguments from * @return if processing command was successful */ bool CmdParser::procCmd_cut_outside(std::istream &strm) { // get layer from arguments and convert to polygons std::string layerName; const Layer *layer; Polygons polys; if (!getLayerPolys(strm, layerName, layer, polys)) return false; // outer offset polygons Polygons newPolys; if (!polys.createOuterOffset(mSettings.tool_diameter * 0.5, newPolys)) { std::cerr << "creating outer offset polygons failed" << std::endl; return false; } // convert polygons back to layer (containing paths) Layer newLayer; newPolys.writeToLayer(newLayer); newLayer.improvePaths(mSettings.precision); // convert layer to G-code newLayer.toGCode(mSettings, mGCode); return true; } /** * @brief process cut_pocket command * @param[in] strm stream to read command arguments from * @return if processing command was successful */ bool CmdParser::procCmd_cut_pocket(std::istream &strm) { // get layer from arguments and convert to polygons std::string layerName; const Layer *layer; Polygons polys; if (!getLayerPolys(strm, layerName, layer, polys)) return false; // fill insides of polygons by creating inner offset polygons Polygons newPolys; if (!polys.fillInnerOffset(mSettings.tool_diameter * 0.5, newPolys)) { std::cerr << "filling insides of polygons failed" << std::endl; return false; } // convert polygons back to layer (containing paths) Layer newLayer; newPolys.writeToLayer(newLayer); newLayer.improvePaths(mSettings.precision); // convert layer to G-code newLayer.toGCode(mSettings, mGCode); return true; } /** * @brief process read_dxf command * @param[in] strm stream to read command arguments from * @return if processing command was successful */ bool CmdParser::procCmd_read_dxf(std::istream &strm) { // get arguments std::string fileName; strm >> fileName; if (strm.fail()) { std::cerr << "missing DXF file name" << std::endl; return false; } // re-base DXF file name fileName = filename_rebase(fileName, mBaseDir); // read DXF file if (!mDrawing.loadDxf(fileName, mSettings.precision)) { std::cerr << "could not read DXF file \"" << fileName << "\"" << std::endl; return false; } // improve paths in layers mDrawing.improvePaths(mSettings.precision); return true; } /** * @brief process set_base_z command * @param[in] strm stream to read command arguments from * @return if processing command was successful */ bool CmdParser::procCmd_set_base_z(std::istream &strm) { // get arguments double z; strm >> z; if (strm.fail()) { std::cerr << "missing z coordinate" << std::endl; return false; } // update settings mSettings.base_z = z; return true; } /** * @brief process set_cut_z command * @param[in] strm stream to read command arguments from * @return if processing command was successful */ bool CmdParser::procCmd_set_cut_z(std::istream &strm) { // get arguments double z; strm >> z; if (strm.fail()) { std::cerr << "missing z coordinate" << std::endl; return false; } // update settings mSettings.cut_z = z; return true; } /** * @brief process set_cut_z_step command * @param[in] strm stream to read command arguments from * @return if processing command was successful */ bool CmdParser::procCmd_set_cut_z_step(std::istream &strm) { // get arguments and check them double z; strm >> z; if (strm.fail()) { std::cerr << "missing z value" << std::endl; return false; } if (z <= 0.0) { std::cerr << "invalid z cut step value (" << z << ", expected > 0.0)" << std::endl; return false; } // update settings mSettings.cut_z_step = z; return true; } /** * @brief process set_dwell_time command * @param[in] strm stream to read command arguments from * @return if processing command was successful */ bool CmdParser::procCmd_set_dwell_time(std::istream &strm) { // get arguments and check them double dwell_time; strm >> dwell_time; if (strm.fail()) { std::cerr << "missing dwell time" << std::endl; return false; } if (dwell_time < 0.0) { std::cerr << "invalid dwell time (" << dwell_time << ", expected >= 0.0)" << std::endl; return false; } // update settings mSettings.dwell_time = dwell_time; return true; } /** * @brief process set_feed_drill command * @param[in] strm stream to read command arguments from * @return if processing command was successful */ bool CmdParser::procCmd_set_feed_drill(std::istream &strm) { // get arguments and check them double feed; strm >> feed; if (strm.fail()) { std::cerr << "missing feed rate" << std::endl; return false; } if (feed <= 0.0) { std::cerr << "invalid feed rate (" << feed << ", expected > 0.0)" << std::endl; return false; } // update settings mSettings.feed_drill = feed; return true; } /** * @brief process set_feed_mill command * @param[in] strm stream to read command arguments from * @return if processing command was successful */ bool CmdParser::procCmd_set_feed_mill(std::istream &strm) { // get arguments and check them double feed; strm >> feed; if (strm.fail()) { std::cerr << "missing feed rate" << std::endl; return false; } if (feed <= 0.0) { std::cerr << "invalid feed rate (" << feed << ", expected > 0.0)" << std::endl; return false; } // update settings mSettings.feed_mill = feed; return true; } /** * @brief process set_layer_mode command * @param[in] strm stream to read command arguments from * @return if processing command was successful */ bool CmdParser::procCmd_set_layer_mode(std::istream &strm) { // get arguments std::string layer_mode_str; strm >> layer_mode_str; if (strm.fail()) { std::cerr << "missing layer mode (\"level_by_level\", \"path_by_path\")" << std::endl; return false; } // check argument and update settings if (layer_mode_str == "level_by_level") { mSettings.layer_mode = Settings::LevelByLevel; return true; } else if (layer_mode_str == "path_by_path") { mSettings.layer_mode = Settings::PathByPath; return true; } else { std::cerr << "invalid layer mode (\"" << layer_mode_str << "\", expected: \"level_by_level\", \"path_by_path\")" << std::endl; return false; } } /** * @brief process set_move_z command * @param[in] strm stream to read command arguments from * @return if processing command was successful */ bool CmdParser::procCmd_set_move_z(std::istream &strm) { // get arguments double z; strm >> z; if (strm.fail()) { std::cerr << "missing z coordinate" << std::endl; return false; } // update settings mSettings.move_z = z; return true; } /** * @brief process set_offset_x command * @param[in] strm stream to read command arguments from * @return if processing command was successful */ bool CmdParser::procCmd_set_offset_x(std::istream &strm) { // get arguments double x; strm >> x; if (strm.fail()) { std::cerr << "missing x coordinate" << std::endl; return false; } // update settings mSettings.offset_x = x; return true; } /** * @brief process set_offset_y command * @param[in] strm stream to read command arguments from * @return if processing command was successful */ bool CmdParser::procCmd_set_offset_y(std::istream &strm) { // get arguments double y; strm >> y; if (strm.fail()) { std::cerr << "missing y coordinate" << std::endl; return false; } // update settings mSettings.offset_y = y; return true; } /** * @brief process set_precision command * @param[in] strm stream to read command arguments from * @return if processing command was successful */ bool CmdParser::procCmd_set_precision(std::istream &strm) { // get arguments and check them double precision; strm >> precision; if (strm.fail()) { std::cerr << "missing precision" << std::endl; return false; } if (precision < 1.0e-8 || precision > 1.0) { std::cerr << "invalid precision (" << precision << ", expected 1.0e-8 ... 1.0)" << std::endl; return false; } // update settings mSettings.precision = precision; return true; } /** * @brief process set_tool_diameter command * @param[in] strm stream to read command arguments from * @return if processing command was successful */ bool CmdParser::procCmd_set_tool_diameter(std::istream &strm) { // get arguments and check them double diameter; strm >> diameter; if (strm.fail()) { std::cerr << "missing tool diameter" << std::endl; return false; } if (diameter < 0.0) { std::cerr << "invalid tool diameter (" << diameter << ", expected >= 0.0)" << std::endl; return false; } // update settings mSettings.tool_diameter = diameter; return true; } /** * @brief process write_ngc command * @param[in] strm stream to read command arguments from * @return if processing command was successful */ bool CmdParser::procCmd_write_ngc(std::istream &strm) { // get arguments std::string fileName; strm >> fileName; if (strm.fail()) { std::cerr << "missing NGC file name" << std::endl; return false; } // re-base NGC file name fileName = filename_rebase(fileName, mBaseDir); // calculate number of digits after decimal point unsigned int digits = (unsigned int)ceil(-log10(mSettings.precision)); // write NGC file if (!mGCode.toFile(fileName, digits)) { std::cerr << "could not write NGC file \"" << fileName << "\"" << std::endl; return false; } return true; } /** * @brief process command from line of text * @param[in] strLine line containing command to process * @return if processing command was successful */ bool CmdParser::procLine(const std::string &strLine) { std::stringstream strm(strLine); // read command std::string cmd; strm >> cmd; if (strm.fail()) return true; // ignore empty lines // commands if (cmd == "cmd") return procCmd_cmd(strm); else if (cmd == "cut") return procCmd_cut(strm); else if (cmd == "cut_inside") return procCmd_cut_inside(strm); else if (cmd == "cut_outside") return procCmd_cut_outside(strm); else if (cmd == "cut_pocket") return procCmd_cut_pocket(strm); else if (cmd == "read_dxf") return procCmd_read_dxf(strm); else if (cmd == "set_base_z") return procCmd_set_base_z(strm); else if (cmd == "set_cut_z") return procCmd_set_cut_z(strm); else if (cmd == "set_cut_z_step") return procCmd_set_cut_z_step(strm); else if (cmd == "set_dwell_time") return procCmd_set_dwell_time(strm); else if (cmd == "set_feed_drill") return procCmd_set_feed_drill(strm); else if (cmd == "set_feed_mill") return procCmd_set_feed_mill(strm); else if (cmd == "set_layer_mode") return procCmd_set_layer_mode(strm); else if (cmd == "set_move_z") return procCmd_set_move_z(strm); else if (cmd == "set_offset_x") return procCmd_set_offset_x(strm); else if (cmd == "set_offset_y") return procCmd_set_offset_y(strm); else if (cmd == "set_precision") return procCmd_set_precision(strm); else if (cmd == "set_tool_diameter") return procCmd_set_tool_diameter(strm); else if (cmd == "write_ngc") return procCmd_write_ngc(strm); else { std::cerr << "unknown command \"" << cmd << "\"" << std::endl; return false; } } /** * @brief process commands from a stream * @param[in] strm stream to process * @param[in] if processing stream was successful * @return if processing commands was successful */ bool CmdParser::procStream(std::istream &strm) { unsigned int lineNo = 0; while (strm.good()) { // read line, remove comment std::string line; std::getline(strm, line); std::string::size_type pos = line.find_first_of("#;"); if (pos != std::string::npos) line.erase(pos); lineNo++; // process line if (!procLine(line)) { std::cerr << "error processing command in line " << lineNo << std::endl; return false; } } return true; } /** * @brief process commands from a file * @param[in] strFileName name of file to process * @param[in] if processing the file was successful * @return if processing commands was successful */ bool CmdParser::procFile(const std::string &strFileName) { std::ifstream ifstrm(strFileName.c_str(), std::ios::in); if (!ifstrm.is_open()) { std::cerr << "could not open \"" << strFileName << "\" for reading" << std::endl; return false; } mBaseDir = filename_get_dir(strFileName); bool ret = procStream(ifstrm); mBaseDir.clear(); return ret; }