GCodeLoader.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. "use strict";
  2. /**
  3. * THREE.GCodeLoader is used to load gcode files usually used for 3D printing or CNC applications.
  4. *
  5. * Gcode files are composed by commands used by machines to create objects.
  6. *
  7. * @class THREE.GCodeLoader
  8. * @param {Manager} manager Loading manager.
  9. * @author tentone
  10. * @author joewalnes
  11. */
  12. THREE.GCodeLoader = function(manager)
  13. {
  14. this.manager = (manager !== undefined) ? manager : THREE.DefaultLoadingManager;
  15. }
  16. THREE.GCodeLoader.prototype.load = function(url, onLoad, onProgress, onError)
  17. {
  18. var self = this;
  19. var loader = new THREE.FileLoader(self.manager);
  20. loader.setPath(this.path);
  21. loader.load(url, function(text)
  22. {
  23. onLoad(self.parse(text));
  24. }, onProgress, onError);
  25. };
  26. THREE.GCodeLoader.prototype.parse = function(data)
  27. {
  28. var currentState = {x:0, y:0, z:0, e:0, f:0, extruding:false};
  29. var currentLayer = undefined;
  30. var relative = false;
  31. var box = new THREE.Box3();
  32. var layers = [];
  33. var pathMaterial = new THREE.LineBasicMaterial({color: 0xFFFF00});
  34. pathMaterial.name = "path";
  35. var extrudingMaterial = new THREE.LineBasicMaterial({color: 0xFFFFFF});
  36. extrudingMaterial.name = "extruded";
  37. function newLayer(line)
  38. {
  39. currentLayer = {lines: [], currentLayer: layers.length, z: line.z};
  40. layers.push(currentLayer);
  41. }
  42. function getLineGroup(line)
  43. {
  44. if(currentLayer === undefined)
  45. {
  46. newLayer(line);
  47. }
  48. var grouptype = line.extruding ? 1 : 0;
  49. if(currentLayer.lines[grouptype] === undefined)
  50. {
  51. currentLayer.lines[grouptype] =
  52. {
  53. type: grouptype,
  54. feed: line.e,
  55. extruding: line.extruding,
  56. geometry: new THREE.Geometry(),
  57. material: line.extruding ? extrudingMaterial : pathMaterial,
  58. segmentCount: 0
  59. };
  60. }
  61. return currentLayer.lines[grouptype];
  62. }
  63. //Create lie segment between p1 and p2
  64. function addSegment(p1, p2)
  65. {
  66. var group = getLineGroup(p2);
  67. var geometry = group.geometry;
  68. group.segmentCount++;
  69. geometry.vertices.push(new THREE.Vector3(p1.x, p1.y, p1.z));
  70. geometry.vertices.push(new THREE.Vector3(p2.x, p2.y, p2.z));
  71. if(p2.extruding)
  72. {
  73. box.min.set(Math.min(box.min.x, p2.x), Math.min(box.min.y, p2.y), Math.min(box.min.z, p2.z));
  74. box.max.set(Math.max(box.max.x, p2.x), Math.max(box.max.y, p2.y), Math.max(box.max.z, p2.z));
  75. }
  76. }
  77. function delta(v1, v2)
  78. {
  79. return relative ? v2 : v2 - v1;
  80. }
  81. function absolute (v1, v2)
  82. {
  83. return relative ? v1 + v2 : v2;
  84. }
  85. var lines = data.replace(/;.+/g,'').split("\n");
  86. for(var i = 0; i < lines.length; i++)
  87. {
  88. var tokens = lines[i].split(" ");
  89. var cmd = tokens[0].toUpperCase();
  90. //Argumments
  91. var args = {};
  92. tokens.splice(1).forEach(function(token)
  93. {
  94. if(token[0] !== undefined)
  95. {
  96. var key = token[0].toLowerCase();
  97. var value = parseFloat(token.substring(1));
  98. args[key] = value;
  99. }
  100. });
  101. //Process commands
  102. //G0/G1 – Linear Movement
  103. if(cmd === "G0" || cmd === "G1")
  104. {
  105. var line =
  106. {
  107. x: args.x !== undefined ? absolute(currentState.x, args.x) : currentState.x,
  108. y: args.y !== undefined ? absolute(currentState.y, args.y) : currentState.y,
  109. z: args.z !== undefined ? absolute(currentState.z, args.z) : currentState.z,
  110. e: args.e !== undefined ? absolute(currentState.e, args.e) : currentState.e,
  111. f: args.f !== undefined ? absolute(currentState.f, args.f) : currentState.f,
  112. };
  113. //Layer change detection is or made by watching Z, it"s made by watching when we extrude at a new Z position
  114. if(delta(currentState.e, line.e) > 0)
  115. {
  116. line.extruding = delta(currentState.e, line.e) > 0;
  117. if(currentLayer == undefined || line.z != currentLayer.z)
  118. {
  119. newLayer(line);
  120. }
  121. }
  122. addSegment(currentState, line);
  123. currentState = line;
  124. }
  125. //G2/G3 - Arc Movement (G2 clock wise and G3 counter clock wise)
  126. else if(cmd === "G2" || cmd === "G3")
  127. {
  128. console.warn("THREE.GCodeLoader: Arc command not supported");
  129. }
  130. //G90: Set to Absolute Positioning
  131. else if(cmd === "G90")
  132. {
  133. relative = false;
  134. }
  135. //G91: Set to Relative Positioning
  136. else if(cmd === "G91")
  137. {
  138. relative = true;
  139. }
  140. //G92: Set Position
  141. else if(cmd === "G92")
  142. {
  143. var line = currentState;
  144. line.x = args.x !== undefined ? args.x : line.x;
  145. line.y = args.y !== undefined ? args.y : line.y;
  146. line.z = args.z !== undefined ? args.z : line.z;
  147. line.e = args.e !== undefined ? args.e : line.e;
  148. currentState = line;
  149. }
  150. else
  151. {
  152. console.warn("THREE.GCodeLoader: Command not supported:" + cmd);
  153. }
  154. }
  155. var object = new THREE.Object3D();
  156. object.name = "gcode";
  157. for(var i = 0; i < layers.length; i++)
  158. {
  159. var layer = layers[i];
  160. for(var j = 0; j < layer.lines.length; j++)
  161. {
  162. var line = layer.lines[j];
  163. if(line !== undefined)
  164. {
  165. var segments = new THREE.LineSegments(line.geometry, line.material);
  166. segments.name = "layer" + i;
  167. object.add(segments);
  168. }
  169. }
  170. }
  171. return object;
  172. };