2dd1ce70bbcde2378fe84d841d08f45c434c0256
Stefan Schuermans initial version, DXFs can b...

Stefan Schuermans authored 11 years ago

1) /* drawing (DXF) to G-code (NGC) converter
2)  * Copyright 2013 Stefan Schuermans <stefan@schuermans.info>
3)  * Copyleft: CC-BY-SA http://creativecommons.org/licenses/by-sa/3.0/
4)  */
5) 
6) #include <fstream>
7) #include <iostream>
Stefan Schuermans configuration of precision

Stefan Schuermans authored 11 years ago

8) #include <math.h>
Stefan Schuermans initial version, DXFs can b...

Stefan Schuermans authored 11 years ago

9) #include <sstream>
10) #include <string>
11) 
12) #include "cmdparser.h"
13) #include "drawing.h"
14) #include "filename.h"
15) #include "gcode.h"
Stefan Schuermans implement converting paths...

Stefan Schuermans authored 11 years ago

16) #include "polygons.h"
Stefan Schuermans initial version, DXFs can b...

Stefan Schuermans authored 11 years ago

17) #include "settings.h"
18) 
Stefan Schuermans implement converting paths...

Stefan Schuermans authored 11 years ago

19) /**
20)  * @brief get layer by name from stream
21)  * @param[in] strm stream to read layer name from
22)  * @param[out] name layer name from stream
23)  * @param[out] layer layer indicated by name from stream
24)  * @return if layer could be found
25)  */
26) bool CmdParser::getLayer(std::istream &strm, std::string &name,
27)                          const Layer *&layer) const
28) {
29)   // get layer name argument
30)   strm >> name;
31)   if (strm.fail()) {
32)     std::cerr << "missing layer name" << std::endl;
33)     return false;
34)   }
35) 
36)   // get layer
37)   Drawing::Layers::const_iterator itLayer = mDrawing.mLayers.find(name);
38)   if (itLayer == mDrawing.mLayers.end()) {
39)     std::cerr << "layer \"" << name << "\" not found" << std::endl;
40)     return false;
41)   }
42)   layer = &itLayer->second;
43) 
44)   return true;
45) }
46) 
47) /**
48)  * @brief get layer by name from stream and convert to polygons
49)  * @param[in] strm stream to read layer name from
50)  * @param[out] name layer name from stream
51)  * @param[out] layer layer indicated by name from stream
52)  * @param[in,out] polys polygons created from layer
53)  * @return if layer could be found and converted to polygons
54)  */
55) bool CmdParser::getLayerPolys(std::istream &strm, std::string &name,
56)                               const Layer *&layer, Polygons &polys) const
57) {
58)   // get layer
59)   if (!getLayer(strm, name, layer))
60)     return false;
61) 
62)   // convert layer to polygons
63)   if (!polys.loadLayer(*layer, mSettings.precision)) {
64)     std::cerr << "cannot convert layer \"" << name << "\" to polygons"
65)               << std::endl;
66)     return false;
67)   }
68) 
69)   return true;
70) }
71) 
Stefan Schuermans initial version, DXFs can b...

Stefan Schuermans authored 11 years ago

72) /**
73)  * @brief process cmd command
74)  * @param[in] strm stream to read command arguments from
75)  * @return if processing command was successful
76)  */
77) bool CmdParser::procCmd_cmd(std::istream &strm)
78) {
79)   // skip whitespace and use rest of line as custom command
80)   strm >> std::ws;
81)   std::string cmd;
82)   getline(strm, cmd);
83) 
84)   // add custom command to G-code
85)   mGCode.appendCustom(cmd);
86) 
87)   return true;
88) }
89) 
90) /**
91)  * @brief process cut command
92)  * @param[in] strm stream to read command arguments from
93)  * @return if processing command was successful
94)  */
95) bool CmdParser::procCmd_cut(std::istream &strm)
96) {
Stefan Schuermans implement converting paths...

Stefan Schuermans authored 11 years ago

97)   // get layer from arguments
Stefan Schuermans initial version, DXFs can b...

Stefan Schuermans authored 11 years ago

98)   std::string layerName;
Stefan Schuermans implement converting paths...

Stefan Schuermans authored 11 years ago

99)   const Layer *layer;
100)   if (!getLayer(strm, layerName, layer))
Stefan Schuermans initial version, DXFs can b...

Stefan Schuermans authored 11 years ago

101)     return false;
102) 
Stefan Schuermans implement converting paths...

Stefan Schuermans authored 11 years ago

103)   // convert layer to G-code
104)   layer->toGCode(mSettings, mGCode);
105) 
106)   return true;
107) }
108) 
109) /**
110)  * @brief process cut_inside command
111)  * @param[in] strm stream to read command arguments from
112)  * @return if processing command was successful
113)  */
114) bool CmdParser::procCmd_cut_inside(std::istream &strm)
115) {
116)   // get layer from arguments and convert to polygons
117)   std::string layerName;
118)   const Layer *layer;
119)   Polygons polys;
120)   if (!getLayerPolys(strm, layerName, layer, polys))
Stefan Schuermans initial version, DXFs can b...

Stefan Schuermans authored 11 years ago

121)     return false;
122) 
Stefan Schuermans implement outer polygon off...

Stefan Schuermans authored 11 years ago

123)   // inner offset polygons
Stefan Schuermans implement inside cutting (h...

Stefan Schuermans authored 11 years ago

124)   Polygons newPolys;
Stefan Schuermans implement outer polygon off...

Stefan Schuermans authored 11 years ago

125)   if (!polys.createInnerOffset(mSettings.tool_diameter * 0.5, newPolys)) {
126)     std::cerr << "creating inner offset polygons failed" << std::endl;
127)     return false;
128)   }
Stefan Schuermans implement inside cutting (h...

Stefan Schuermans authored 11 years ago

129) 
130)   // convert polygons back to layer (containing paths)
Stefan Schuermans implement converting polygo...

Stefan Schuermans authored 11 years ago

131)   Layer newLayer;
Stefan Schuermans implement inside cutting (h...

Stefan Schuermans authored 11 years ago

132)   newPolys.writeToLayer(newLayer);
Stefan Schuermans implement converting polygo...

Stefan Schuermans authored 11 years ago

133) 
134)   // convert layer to G-code
135)   newLayer.toGCode(mSettings, mGCode);
Stefan Schuermans implement converting paths...

Stefan Schuermans authored 11 years ago

136) 
137)   return true;
138) }
139) 
140) /**
141)  * @brief process cut_outside command
142)  * @param[in] strm stream to read command arguments from
143)  * @return if processing command was successful
144)  */
145) bool CmdParser::procCmd_cut_outside(std::istream &strm)
146) {
147)   // get layer from arguments and convert to polygons
148)   std::string layerName;
149)   const Layer *layer;
150)   Polygons polys;
151)   if (!getLayerPolys(strm, layerName, layer, polys))
152)     return false;
153) 
Stefan Schuermans implement outer polygon off...

Stefan Schuermans authored 11 years ago

154)   // outer offset polygons
155)   Polygons newPolys;
156)   if (!polys.createOuterOffset(mSettings.tool_diameter * 0.5, newPolys)) {
157)     std::cerr << "creating outer offset polygons failed" << std::endl;
158)     return false;
159)   }
160) 
161)   // convert polygons back to layer (containing paths)
Stefan Schuermans implement converting polygo...

Stefan Schuermans authored 11 years ago

162)   Layer newLayer;
Stefan Schuermans implement outer polygon off...

Stefan Schuermans authored 11 years ago

163)   newPolys.writeToLayer(newLayer);
Stefan Schuermans implement converting polygo...

Stefan Schuermans authored 11 years ago

164) 
165)   // convert layer to G-code
166)   newLayer.toGCode(mSettings, mGCode);
Stefan Schuermans implement converting paths...

Stefan Schuermans authored 11 years ago

167) 
168)   return true;
169) }
170) 
171) /**
172)  * @brief process cut_pocket command
173)  * @param[in] strm stream to read command arguments from
174)  * @return if processing command was successful
175)  */
176) bool CmdParser::procCmd_cut_pocket(std::istream &strm)
177) {
178)   // get layer from arguments and convert to polygons
179)   std::string layerName;
180)   const Layer *layer;
181)   Polygons polys;
182)   if (!getLayerPolys(strm, layerName, layer, polys))
183)     return false;
184) 
Stefan Schuermans implement filling polygon w...

Stefan Schuermans authored 11 years ago

185)   // fill insides of polygons by creating inner offset polygons
186)   Polygons newPolys;
187)   if (!polys.fillInnerOffset(mSettings.tool_diameter * 0.5, newPolys)) {
188)     std::cerr << "filling insides of polygons failed" << std::endl;
189)     return false;
190)   }
191) 
192)   // convert polygons back to layer (containing paths)
Stefan Schuermans implement converting polygo...

Stefan Schuermans authored 11 years ago

193)   Layer newLayer;
Stefan Schuermans implement filling polygon w...

Stefan Schuermans authored 11 years ago

194)   newPolys.writeToLayer(newLayer);
Stefan Schuermans implement converting polygo...

Stefan Schuermans authored 11 years ago

195) 
196)   // convert layer to G-code
197)   newLayer.toGCode(mSettings, mGCode);
Stefan Schuermans initial version, DXFs can b...

Stefan Schuermans authored 11 years ago

198) 
199)   return true;
200) }
201) 
202) /**
203)  * @brief process read_dxf command
204)  * @param[in] strm stream to read command arguments from
205)  * @return if processing command was successful
206)  */
207) bool CmdParser::procCmd_read_dxf(std::istream &strm)
208) {
209)   // get arguments
210)   std::string fileName;
211)   strm >> fileName;
212)   if (strm.fail()) {
213)     std::cerr << "missing DXF file name" << std::endl;
214)     return false;
215)   }
216) 
217)   // re-base DXF file name
218)   fileName = filename_rebase(fileName, mBaseDir);
219) 
220)   // read DXF file
221)   if (!mDrawing.loadDxf(fileName)) {
222)     std::cerr << "could not read DXF file \"" << fileName << "\""
223)               << std::endl;
224)     return false;
225)   }
226) 
Stefan Schuermans implement joining and impro...

Stefan Schuermans authored 11 years ago

227)   // improve paths in layers
228)   mDrawing.improvePaths(mSettings.precision);
229) 
Stefan Schuermans initial version, DXFs can b...

Stefan Schuermans authored 11 years ago

230)   return true;
231) }
232) 
233) /**
234)  * @brief process set_base_z command
235)  * @param[in] strm stream to read command arguments from
236)  * @return if processing command was successful
237)  */
238) bool CmdParser::procCmd_set_base_z(std::istream &strm)
239) {
240)   // get arguments
241)   double z;
242)   strm >> z;
243)   if (strm.fail()) {
244)     std::cerr << "missing z coordinate" << std::endl;
245)     return false;
246)   }
247) 
248)   // update settings
249)   mSettings.base_z = z;
250)   return true;
251) }
252) 
253) /**
254)  * @brief process set_cut_z command
255)  * @param[in] strm stream to read command arguments from
256)  * @return if processing command was successful
257)  */
258) bool CmdParser::procCmd_set_cut_z(std::istream &strm)
259) {
260)   // get arguments
261)   double z;
262)   strm >> z;
263)   if (strm.fail()) {
264)     std::cerr << "missing z coordinate" << std::endl;
265)     return false;
266)   }
267) 
268)   // update settings
269)   mSettings.cut_z = z;
270)   return true;
271) }
272) 
273) /**
274)  * @brief process set_cut_z_step command
275)  * @param[in] strm stream to read command arguments from
276)  * @return if processing command was successful
277)  */
278) bool CmdParser::procCmd_set_cut_z_step(std::istream &strm)
279) {
280)   // get arguments and check them
281)   double z;
282)   strm >> z;
283)   if (strm.fail()) {
284)     std::cerr << "missing z value" << std::endl;
285)     return false;
286)   }
287)   if (z <= 0.0) {
288)     std::cerr << "invalid z cut step value (" << z << ")" << std::endl;
289)     return false;
290)   }
291) 
292)   // update settings
293)   mSettings.cut_z_step = z;
294)   return true;
295) }
296) 
297) /**
298)  * @brief process set_feed_drill command
299)  * @param[in] strm stream to read command arguments from
300)  * @return if processing command was successful
301)  */
302) bool CmdParser::procCmd_set_feed_drill(std::istream &strm)
303) {
304)   // get arguments and check them
305)   double feed;
306)   strm >> feed;
307)   if (strm.fail()) {
308)     std::cerr << "missing feed rate" << std::endl;
309)     return false;
310)   }
311)   if (feed <= 0.0) {
312)     std::cerr << "invalid feed rate (" << feed << ")" << std::endl;
313)     return false;
314)   }
315) 
316)   // update settings
317)   mSettings.feed_drill = feed;
318)   return true;
319) }
320) 
321) /**
322)  * @brief process set_feed_mill command
323)  * @param[in] strm stream to read command arguments from
324)  * @return if processing command was successful
325)  */
326) bool CmdParser::procCmd_set_feed_mill(std::istream &strm)
327) {
328)   // get arguments and check them
329)   double feed;
330)   strm >> feed;
331)   if (strm.fail()) {
332)     std::cerr << "missing feed rate" << std::endl;
333)     return false;
334)   }
335)   if (feed <= 0.0) {
336)     std::cerr << "invalid feed rate (" << feed << ")" << std::endl;
337)     return false;
338)   }
339) 
340)   // update settings
341)   mSettings.feed_mill = feed;
342)   return true;
343) }
344) 
345) /**
346)  * @brief process set_move_z command
347)  * @param[in] strm stream to read command arguments from
348)  * @return if processing command was successful
349)  */
350) bool CmdParser::procCmd_set_move_z(std::istream &strm)
351) {
352)   // get arguments
353)   double z;
354)   strm >> z;
355)   if (strm.fail()) {
356)     std::cerr << "missing z coordinate" << std::endl;
357)     return false;
358)   }
359) 
360)   // update settings
361)   mSettings.move_z = z;
362)   return true;
363) }
364) 
Stefan Schuermans configuration of precision

Stefan Schuermans authored 11 years ago

365) /**
366)  * @brief process set_precision command
367)  * @param[in] strm stream to read command arguments from
368)  * @return if processing command was successful
369)  */
370) bool CmdParser::procCmd_set_precision(std::istream &strm)
371) {
372)   // get arguments and check them
373)   double precision;
374)   strm >> precision;
375)   if (strm.fail()) {
376)     std::cerr << "missing precision" << std::endl;
377)     return false;
378)   }
379)   if (precision < 1.0e-8 || precision > 1.0) {
380)     std::cerr << "invalid precision (" << precision << ")" << std::endl;
381)     return false;
382)   }
383) 
384)   // update settings
385)   mSettings.precision = precision;
386)   return true;
387) }
388) 
Stefan Schuermans initial version, DXFs can b...

Stefan Schuermans authored 11 years ago

389) /**
390)  * @brief process set_tool_diameter command
391)  * @param[in] strm stream to read command arguments from
392)  * @return if processing command was successful
393)  */
394) bool CmdParser::procCmd_set_tool_diameter(std::istream &strm)
395) {
396)   // get arguments and check them
397)   double diameter;
398)   strm >> diameter;
399)   if (strm.fail()) {
400)     std::cerr << "missing tool diameter" << std::endl;
401)     return false;
402)   }
403)   if (diameter < 0.0) {
404)     std::cerr << "invalid tool diameter (" << diameter << ")" << std::endl;
405)     return false;
406)   }
407) 
408)   // update settings
409)   mSettings.tool_diameter = diameter;
410)   return true;
411) }
412) 
413) /**
414)  * @brief process write_ngc command
415)  * @param[in] strm stream to read command arguments from
416)  * @return if processing command was successful
417)  */
418) bool CmdParser::procCmd_write_ngc(std::istream &strm)
419) {
420)   // get arguments
421)   std::string fileName;
422)   strm >> fileName;
423)   if (strm.fail()) {
424)     std::cerr << "missing NGC file name" << std::endl;
425)     return false;
426)   }
427) 
428)   // re-base NGC file name
429)   fileName = filename_rebase(fileName, mBaseDir);
430) 
Stefan Schuermans configuration of precision

Stefan Schuermans authored 11 years ago

431)   // calculate number of digits after decimal point
432)   unsigned int digits = (unsigned int)ceil(-log10(mSettings.precision));
433) 
Stefan Schuermans initial version, DXFs can b...

Stefan Schuermans authored 11 years ago

434)   // write NGC file
Stefan Schuermans configuration of precision

Stefan Schuermans authored 11 years ago

435)   if (!mGCode.toFile(fileName, digits)) {
Stefan Schuermans initial version, DXFs can b...

Stefan Schuermans authored 11 years ago

436)     std::cerr << "could not write NGC file \"" << fileName << "\""
437)               << std::endl;
438)     return false;
439)   }
440) 
441)   return true;
442) }
443) 
444) /**
445)  * @brief process command from line of text
446)  * @param[in] strLine line containing command to process
447)  * @return if processing command was successful
448)  */
449) bool CmdParser::procLine(const std::string &strLine)
450) {
451)   std::stringstream strm(strLine);
452) 
453)   // read command
454)   std::string cmd;
455)   strm >> cmd;
456)   if (strm.fail())
457)     return true; // ignore empty lines
458) 
459)   // commands
460)   if (cmd == "cmd")
461)     return procCmd_cmd(strm);
462)   else if (cmd == "cut")
463)     return procCmd_cut(strm);
Stefan Schuermans implement converting paths...

Stefan Schuermans authored 11 years ago

464)   else if (cmd == "cut_inside")
465)     return procCmd_cut_inside(strm);
466)   else if (cmd == "cut_outside")
467)     return procCmd_cut_outside(strm);
468)   else if (cmd == "cut_pocket")
469)     return procCmd_cut_pocket(strm);
Stefan Schuermans initial version, DXFs can b...

Stefan Schuermans authored 11 years ago

470)   else if (cmd == "read_dxf")
471)     return procCmd_read_dxf(strm);
472)   else if (cmd == "set_base_z")
473)     return procCmd_set_base_z(strm);
474)   else if (cmd == "set_cut_z")
475)     return procCmd_set_cut_z(strm);
476)   else if (cmd == "set_cut_z_step")
477)     return procCmd_set_cut_z_step(strm);
478)   else if (cmd == "set_feed_drill")
479)     return procCmd_set_feed_drill(strm);
480)   else if (cmd == "set_feed_mill")
481)     return procCmd_set_feed_mill(strm);
482)   else if (cmd == "set_move_z")
483)     return procCmd_set_move_z(strm);
Stefan Schuermans configuration of precision

Stefan Schuermans authored 11 years ago

484)   else if (cmd == "set_precision")
485)     return procCmd_set_precision(strm);