├── GcodeViewParse.java ├── LineSegment.java ├── ProcessingGcodeViewer.pde ├── code ├── GcodeViewParse.java ├── LineSegment.java └── vecmath.jar └── data ├── Merged.gcode └── RectangularServoHorn2.gcode /GcodeViewParse.java: -------------------------------------------------------------------------------- 1 | import java.util.List; 2 | import java.util.ArrayList; 3 | import java.util.Arrays; 4 | 5 | import javax.vecmath.Point3f; 6 | 7 | 8 | public class GcodeViewParse { 9 | private static boolean debugVals = false; 10 | private static float extremes[] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; // -x, -y, -z, x, y, z 11 | public GcodeViewParse() 12 | { 13 | 14 | } 15 | 16 | public float[] getExtremes() 17 | { 18 | return extremes; 19 | } 20 | private void testExtremes(Point3f p3f) 21 | { 22 | testExtremes(p3f.x, p3f.y, p3f.z); 23 | 24 | } 25 | private void testExtremes(float x, float y, float z) 26 | { 27 | if(x < extremes[0]) 28 | { 29 | extremes[0] = x; 30 | } 31 | if(x > extremes[3]) 32 | { 33 | extremes[3] = x; 34 | } 35 | if(y < extremes[1]) 36 | { 37 | extremes[1] = y; 38 | } 39 | if(y > extremes[4]) 40 | { 41 | extremes[4] = y; 42 | } 43 | if(z < extremes[2]) 44 | { 45 | extremes[2] = z; 46 | } 47 | if(z > extremes[5]) 48 | { 49 | extremes[5] = z; 50 | } 51 | 52 | } 53 | public ArrayList toObj(ArrayList gcode) 54 | { 55 | float speed = 2; //DEFAULTS to 2 56 | Point3f lastPoint = null; 57 | Point3f curPoint = null; 58 | int curLayer = 0; 59 | int curToolhead = 0; 60 | float parsedX, parsedY, parsedZ, parsedF; 61 | float tolerance = .0002f; 62 | ArrayList lines = new ArrayList(); 63 | float[] lastCoord = { 0.0f, 0.0f, 0.0f}; 64 | boolean currentExtruding = false; 65 | for(String s : gcode) 66 | { 67 | if(s.matches(".*M101.*")) 68 | { 69 | currentExtruding = true; 70 | } 71 | if(s.matches(".*M103.*")) 72 | { 73 | currentExtruding = false; 74 | } 75 | if(s.matches("\\(\\\\)")) 76 | { 77 | curLayer++; 78 | } 79 | if(s.matches(".*T0.*")) 80 | { 81 | curToolhead = 0; 82 | } 83 | if(s.matches(".*T1.*")) 84 | { 85 | curToolhead = 1; 86 | } 87 | if (s.matches(".*G1.*")) 88 | { 89 | String[] sarr = s.split(" "); 90 | parsedX = parseCoord(sarr, 'X'); 91 | parsedY = parseCoord(sarr, 'Y'); 92 | parsedZ = parseCoord(sarr, 'Z'); 93 | parsedF = parseCoord(sarr, 'F'); 94 | 95 | //System.out.println(Arrays.toString(sarr)); 96 | if(!Float.isNaN(parsedX)) 97 | { 98 | lastCoord[0] = parsedX; 99 | } 100 | if(!Float.isNaN(parsedY)) 101 | { 102 | lastCoord[1] = parsedY; 103 | } 104 | if(!Float.isNaN(parsedZ)) 105 | { 106 | /* 107 | if (!(Math.abs(parsedZ - lastCoord[2]) <= tolerance)) 108 | { 109 | curLayer++; 110 | } 111 | */ 112 | lastCoord[2] = parsedZ; 113 | 114 | } 115 | if(!Float.isNaN(parsedF)) 116 | { 117 | speed = parsedF; 118 | } 119 | if(!(Float.isNaN(lastCoord [0]) || Float.isNaN(lastCoord [1]) || Float.isNaN(lastCoord [2]))) 120 | { 121 | 122 | if(debugVals) 123 | { 124 | System.out.println(lastCoord[0] + "," + lastCoord [1] + "," + lastCoord[2] + ", speed =" + speed + 125 | ", layer=" + curLayer); 126 | } 127 | curPoint = new Point3f(lastCoord[0], lastCoord[1], lastCoord[2]); 128 | if(currentExtruding && curLayer > 5) 129 | { 130 | testExtremes(curPoint); 131 | } 132 | if(lastPoint != null) 133 | { 134 | 135 | lines.add(new LineSegment(lastPoint, curPoint, curLayer, speed, curToolhead, currentExtruding)); 136 | } 137 | lastPoint = curPoint; 138 | } 139 | } 140 | 141 | } 142 | return lines; 143 | 144 | } 145 | 146 | 147 | private float parseCoord(String[] sarr, char c) 148 | { 149 | for(String t : sarr) 150 | { 151 | if(t.matches("\\s*[" + c + "]\\s*-*[\\d|\\.]+")) 152 | { 153 | //System.out.println("te : " + t); 154 | return Float.parseFloat(t.substring(1,t.length())); 155 | } 156 | } 157 | return Float.NaN; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /LineSegment.java: -------------------------------------------------------------------------------- 1 | import javax.vecmath.Point3f; 2 | 3 | public class LineSegment { 4 | 5 | private int layer; 6 | private int toolhead = 0; //DEFAULT TOOLHEAD ASSUMED TO BE 0! 7 | private float speed; 8 | private Point3f first, second; 9 | private boolean isExtruding; 10 | 11 | public LineSegment (Point3f a,Point3f b, int layernum, float speedz) 12 | { 13 | first = a; 14 | second = b; 15 | layer = layernum; 16 | speed = speedz; 17 | } 18 | public LineSegment (Point3f a,Point3f b, int layernum, float speedz, boolean extrudz) 19 | { 20 | first = a; 21 | second = b; 22 | layer = layernum; 23 | speed = speedz; 24 | isExtruding = extrudz; 25 | } 26 | public LineSegment(float x1, float y1, float z1, float x2, float y2, float z2, int layernum, float speedz) 27 | { 28 | first = new Point3f(x1, y1, z1); 29 | second = new Point3f(x2, y2, z2); 30 | layernum = layer; 31 | speed = speedz; 32 | } 33 | public LineSegment (Point3f a,Point3f b, int layernum, float speedz, int toolheadz) 34 | { 35 | first = a; 36 | second = b; 37 | layer = layernum; 38 | speed = speedz; 39 | toolhead = toolheadz; 40 | } 41 | public LineSegment(float x1, float y1, float z1, float x2, float y2, float z2, int layernum, float speedz, int toolheadz) 42 | { 43 | first = new Point3f(x1, y1, z1); 44 | second = new Point3f(x2, y2, z2); 45 | layernum = layer; 46 | speed = speedz; 47 | toolhead = toolheadz; 48 | } 49 | public LineSegment (Point3f a,Point3f b, int layernum, float speedz, int toolheadz, boolean extrudz) 50 | { 51 | first = a; 52 | second = b; 53 | layer = layernum; 54 | speed = speedz; 55 | toolhead = toolheadz; 56 | isExtruding = extrudz; 57 | } 58 | public LineSegment(float x1, float y1, float z1, float x2, float y2, float z2, int layernum, float speedz, int toolheadz, boolean extrudz) 59 | { 60 | first = new Point3f(x1, y1, z1); 61 | second = new Point3f(x2, y2, z2); 62 | layernum = layer; 63 | speed = speedz; 64 | toolhead = toolheadz; 65 | isExtruding = extrudz; 66 | 67 | } 68 | public Point3f[] getPointArray() 69 | { 70 | Point3f[] pointarr = { first, second }; 71 | return pointarr; 72 | } 73 | public float[] getPoints() 74 | { 75 | float[] points = {first.x, first.y, first.z , second.x, second.y, second.z }; 76 | return points; 77 | } 78 | public int getToolhead() 79 | { 80 | return toolhead; 81 | } 82 | public float getSpeed() 83 | { 84 | return speed; 85 | } 86 | public int getLayer() 87 | { 88 | return layer; 89 | } 90 | public boolean getExtruding() 91 | { 92 | return isExtruding; 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /ProcessingGcodeViewer.pde: -------------------------------------------------------------------------------- 1 | /* 2 | Author: Noah Levy 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses. 16 | */ 17 | import java.io.BufferedReader; 18 | import java.io.File; 19 | import java.io.FileReader; 20 | import java.io.IOException; 21 | import java.util.ArrayList; 22 | 23 | 24 | import javax.swing.JFileChooser; 25 | import javax.swing.JFrame; 26 | import javax.swing.filechooser.FileFilter; 27 | import javax.swing.filechooser.FileNameExtensionFilter; 28 | import javax.vecmath.Point3f; 29 | import javax.media.opengl.*; 30 | import javax.swing.*; 31 | 32 | import peasy.PeasyCam; 33 | 34 | import controlP5.*; 35 | import processing.opengl.*; 36 | 37 | 38 | private boolean dualExtrusionColoring = false ; 39 | 40 | PeasyCam cam; //The camera object, PeasyCam extends the default processing camera and enables user interaction 41 | ControlP5 controlP5; //ControlP5 object, ControlP5 is a library used for drawing GUI items 42 | PMatrix3D currCameraMatrix; //By having 2 camera matrix I'm able to switch a 3D pannable area and a fixed gui in relation to the user 43 | PGraphicsOpenGL g3; //The graphics object, necessary for openGL manipulations 44 | ControlGroup panButts; //The group of controlP5 buttons related to panning 45 | private boolean is2D = false; 46 | private boolean isDrawable = false; //True if a file is loaded; false if not 47 | private boolean isPlatformed = false; 48 | private boolean isSpeedColored = true; 49 | private String gCode; //The path of the gcode File 50 | private ArrayList objCommands; //An ArrayList of linesegments composing the model 51 | private int curScale = 20; 52 | private int curLayer = 0; 53 | 54 | 55 | ////////////ALPHA VALUES////////////// 56 | 57 | private final int TRANSPARENT = 20; 58 | private final int SOLID = 100; 59 | private final int SUPERSOLID = 255; 60 | 61 | ////////////////////////////////////// 62 | 63 | ////////////COLOR VALUES///////////// 64 | 65 | 66 | private final int RED = color(255,200,200); 67 | private final int BLUE = color(0, 255, 255); 68 | private final int PURPLE = color(242, 0, 255); 69 | private final int YELLOW = color(237, 255, 0); 70 | private final int OTHER_YELLOW = color(234, 212, 7); 71 | private final int GREEN = color(33, 255, 0); 72 | private final int WHITE = color(255, 255, 255); 73 | 74 | ////////////////////////////////////// 75 | 76 | ///////////SPEED VALUES/////////////// 77 | 78 | private float LOW_SPEED = 700; 79 | private float MEDIUM_SPEED = 1400; 80 | private float HIGH_SPEED = 1900; 81 | 82 | ////////////////////////////////////// 83 | 84 | //////////SLIDER VALUES///////////// 85 | 86 | private int minSlider = 1; 87 | private int maxSlider; 88 | private int defaultValue; 89 | 90 | //////////////////////////////////// 91 | 92 | /////////Canvas Size/////////////// 93 | 94 | private int xSize = 5*screen.width/6; 95 | private int ySize = 5*screen.height/6; 96 | 97 | //////////////////////////////////// 98 | private int camOffset = 70; 99 | private int textBoxOffset = 200; 100 | 101 | /* 102 | private static String argument =null; 103 | 104 | 105 | public static void main(String args[]) { 106 | PApplet.main(new String[] {"ProcessingGcodeViewer" }); 107 | if(args.length >= 1) 108 | { 109 | argument = args[0]; 110 | } 111 | } 112 | */ 113 | 114 | 115 | public void setup() { 116 | 117 | //gCode = ("RectangularServoHorn2.gcode"); 118 | //gCode = ("C:/Users/noah/Downloads/RoboArm/pig.gcode"); 119 | //gCode = ("C:/Users/noah/Dropbox/Rep26Stuff/Example Files/Cupcake/Merged.gcode"); 120 | size(xSize,ySize, OPENGL); //OpenGL is the renderer; untested with p3d 121 | frameRate(25); 122 | hint(ENABLE_NATIVE_FONTS); //I've found this hint prevents some weird ControlP5 font not in box issues. 123 | background(0); //Make background black 124 | 125 | g3 = (PGraphicsOpenGL)g; 126 | hint(DISABLE_OPENGL_2X_SMOOTH); //AntiAliasing really hurts performance and I've found it to be distracting when on 127 | noSmooth(); 128 | /* 129 | GL gl = g3.beginGL(); // always use the GL object returned by beginGL 130 | gl.glHint(gl.GL_CLIP_VOLUME_CLIPPING_HINT_EXT, gl.GL_FASTEST); //This line does not work with discrete graphcis 131 | g3.endGL(); 132 | */ 133 | setupCamera(); 134 | 135 | controlP5 = new ControlP5(this); 136 | 137 | /* 138 | Textfield lowField = controlP5.addTextfield("lowSpeed",textBoxOffset,30,40,20); 139 | Textfield mediumField = controlP5.addTextfield("mediumSpeed",textBoxOffset + 60,30,40,20); 140 | Textfield highField = controlP5.addTextfield("highSpeed",textBoxOffset + 120,30,40,20); 141 | lowField.setText(Float.toString(LOW_SPEED)); 142 | mediumField.setText(Float.toString(MEDIUM_SPEED)); 143 | highField.setText(Float.toString(HIGH_SPEED)); 144 | */ 145 | 146 | CheckBox cb = controlP5.addCheckBox("2DBox", width - 200, 38); //The object that contains the gui checkoxes 147 | cb.addItem("2D View",0); 148 | cb.addItem("Enable DualExtrusion Coloring",0); 149 | cb.addItem("Show Platform",0); 150 | //cb.addItem("Consecutive Coloring",0); 151 | // cb.addItem("Full Screen",0); 152 | controlP5.setAutoDraw(false); //THIS IS VERY IMPORTANT, this allows me to designate specifically when the GUI gets drawn, without this and my gui() method the buttons would exist in the 3D plane with everything else 153 | controlP5.addButton("Choose File...",10f,(width - 110),30,80,20); //Opens JFileChooser 154 | 155 | make3D(); //By default the model should be displayed in 3D 156 | if(gCode != null) 157 | { 158 | generateObject(); 159 | } 160 | } 161 | public void controlEvent(ControlEvent theEvent) 162 | { 163 | if(theEvent.isGroup()) 164 | { 165 | if(theEvent.group().name() == "2DBox") 166 | { 167 | int i = 0; 168 | int choice2D = (int)theEvent.group().arrayValue()[0]; 169 | println("2D view is" + choice2D); 170 | if(choice2D == 1) 171 | { 172 | make2D(); 173 | } 174 | if(choice2D == 0) 175 | { 176 | make3D(); 177 | } 178 | int dualChoice = (int)theEvent.group().arrayValue()[1]; 179 | 180 | if(dualChoice == 1) 181 | { 182 | dualExtrusionColoring = true; 183 | 184 | } 185 | if(dualChoice == 0) 186 | { 187 | dualExtrusionColoring = false; 188 | } 189 | int platformChoice = (int)theEvent.group().arrayValue()[2]; 190 | if(platformChoice == 1) 191 | { 192 | isPlatformed = true; 193 | 194 | } 195 | if(platformChoice == 0) 196 | { 197 | isPlatformed = false; 198 | } 199 | } 200 | } 201 | else if(theEvent.controller().name() == "Choose File...") 202 | { 203 | selectFile(); 204 | } 205 | else if(theEvent.controller().name() == "lowSpeed") 206 | { 207 | LOW_SPEED = Float.parseFloat(theEvent.controller().stringValue()); 208 | } 209 | else if(theEvent.controller().name() == "mediumSpeed") 210 | { 211 | MEDIUM_SPEED = Float.parseFloat(theEvent.controller().stringValue()); 212 | } 213 | else if(theEvent.controller().name() == "highSpeed") 214 | { 215 | HIGH_SPEED = Float.parseFloat(theEvent.controller().stringValue()); 216 | } 217 | else 218 | { 219 | float pos[] = cam.getLookAt(); 220 | if(theEvent.controller().name() == "Left") 221 | { 222 | cam.lookAt(pos[0] - 1,pos[1],pos[2],0); 223 | } 224 | else if(theEvent.controller().name() == "Up") 225 | { 226 | cam.lookAt(pos[0],pos[1] - 1,pos[2],0); 227 | } 228 | else if(theEvent.controller().name() == "Right") 229 | { 230 | cam.lookAt(pos[0] + 1,pos[1],pos[2],0); 231 | } 232 | else if(theEvent.controller().name() == "Down") 233 | { 234 | cam.lookAt(pos[0],pos[1] + 1,pos[2],0); 235 | } 236 | } 237 | } 238 | public void make2D() 239 | { 240 | is2D = true; 241 | cam.reset(); 242 | cam.setActive(false); 243 | if(panButts == null) 244 | { 245 | panButts = panButtons(); 246 | } 247 | } 248 | public void make3D() 249 | { 250 | is2D = false; 251 | cam.rotateX(-.37); //Make it obvious it is 3d to start 252 | cam.rotateY(.1); 253 | cam.setActive(true); 254 | 255 | controlP5.remove("Pan Buttons"); 256 | panButts = null; 257 | } 258 | public void generateObject() 259 | { 260 | scale(1, -1, 1); //orient cooridnate plane right-handed props to whosawwhatsis for discovering this 261 | 262 | GcodeViewParse gcvp = new GcodeViewParse(); 263 | objCommands = (gcvp.toObj(readFiletoArrayList(gCode))); 264 | float bounds[] = gcvp.getExtremes(); 265 | System.out.println("Object bounds = " + Arrays.toString(bounds)); 266 | float cent[] = findCenter(bounds); 267 | System.out.println("Center = " + Arrays.toString(cent)); 268 | //cam.lookAt(-1*bounds[0], -1*bounds[1], 0, camOffset); 269 | println("objComBumands :" + objCommands.size()); 270 | maxSlider = objCommands.get(objCommands.size() - 1).getLayer() - 1; // Maximum slider value is highest layer 271 | defaultValue = maxSlider; 272 | controlP5.remove("Layer Slider"); 273 | controlP5.addSlider("Layer Slider",minSlider,maxSlider,defaultValue,20,100,10,300).setNumberOfTickMarks(maxSlider); 274 | //controlP5.addControlWindow("ControlWindow", 50, 50, 20, 20); 275 | 276 | curLayer = (int)Math.round(controlP5.controller("Layer Slider").value()); 277 | isDrawable = true; 278 | } 279 | private float[] findCenter(float[] bounds) 280 | { 281 | float cent[] = {(bounds[0] + bounds[3]),(bounds[1] + bounds[4]),(bounds[2] + bounds[5])}; 282 | return cent; 283 | } 284 | private void setupCamera() 285 | { 286 | setupCamera(0,0); 287 | } 288 | private void setupCamera(float centerX, float centerY) 289 | { 290 | float fov = PI/3.0; 291 | float cameraZ = (height/2.0) / tan(fov/2.0); 292 | perspective(fov, float(width)/float(height), 0.1, cameraZ*10.0); //Calling perspective allows me to set 0.1 as the frustum's zNear which prevents a bunch of clipping issues. 293 | cam = new PeasyCam(this, centerX, centerY, 0, camOffset); // parent, x, y, z, initial distance 294 | 295 | cam.setMinimumDistance(2); 296 | cam.setMaximumDistance(200); 297 | cam.setResetOnDoubleClick(false); 298 | 299 | } 300 | public ControlGroup panButtons() 301 | { 302 | ControlGroup panButts = controlP5.addGroup("Pan Buttons",20,height - 100); 303 | panButts.hideBar(); 304 | //DragHandler panHandle = cam.getPanDragHandler(); 305 | controlP5.addBang("Up",30,4,20,20).setGroup(panButts); 306 | controlP5.addBang("Left",0,34,20,20).setGroup(panButts); 307 | controlP5.addBang("Right",60,34,20,20).setGroup(panButts); 308 | controlP5.addBang("Down",30,64,20,20).setGroup(panButts); 309 | return panButts; 310 | } 311 | public void draw() { 312 | lights(); 313 | //directionalLight(255, 255, 255, -1, 0, 0); 314 | //spotLight(51, 102, 126, 80, 20, 40, -1, 0, 0, PI/2, 2); 315 | 316 | //ambientLight(255,255,255); 317 | background(0); 318 | 319 | hint(ENABLE_DEPTH_TEST); 320 | pushMatrix(); 321 | noSmooth(); 322 | if(isPlatformed) 323 | { 324 | fill(6,13,137); 325 | beginShape(); 326 | vertex(-50,-50,0); 327 | vertex(-50,50,0); 328 | vertex(50,50,0); 329 | vertex(50,-50,0); 330 | endShape(); 331 | noFill(); 332 | } 333 | if(isDrawable) 334 | { 335 | scale(1, -1, 1); //orient cooridnate plane right-handed props to whosawwhatsis for discovering this 336 | 337 | float[] points = new float[6]; 338 | 339 | int maxLayer = (int)Math.round(controlP5.controller("Layer Slider").value()); 340 | 341 | int curTransparency = 0; 342 | int curColor = 0; 343 | beginShape(LINES); 344 | for(LineSegment ls : objCommands) 345 | { 346 | if(ls.getLayer() < maxLayer) 347 | { 348 | curTransparency = SOLID; 349 | } 350 | if(ls.getLayer() == maxLayer) 351 | { 352 | curTransparency = SUPERSOLID; 353 | } 354 | if(ls.getLayer() > maxLayer) 355 | { 356 | curTransparency = TRANSPARENT; 357 | } 358 | if(!ls.getExtruding()) 359 | { 360 | stroke(WHITE,TRANSPARENT); 361 | } 362 | if(!dualExtrusionColoring) 363 | { 364 | if(ls.getExtruding()) 365 | { 366 | if(isSpeedColored) 367 | { 368 | if(ls.getSpeed() > LOW_SPEED && ls.getSpeed() < MEDIUM_SPEED) 369 | { 370 | stroke(PURPLE, curTransparency); 371 | } 372 | if(ls.getSpeed() > MEDIUM_SPEED && ls.getSpeed() < HIGH_SPEED) 373 | { 374 | stroke(BLUE, curTransparency); 375 | } 376 | else if(ls.getSpeed() >= HIGH_SPEED) 377 | { 378 | stroke(OTHER_YELLOW, curTransparency); 379 | } 380 | else //Very low speed.... 381 | { 382 | stroke(GREEN, curTransparency); 383 | } 384 | } 385 | if(!isSpeedColored) 386 | { 387 | if(curColor == 0) 388 | { 389 | stroke(GREEN, SUPERSOLID); 390 | } 391 | if(curColor == 1) 392 | { 393 | stroke(RED, SUPERSOLID); 394 | } 395 | if(curColor == 2) 396 | { 397 | stroke(BLUE, SUPERSOLID); 398 | } 399 | if(curColor == 3) 400 | { 401 | stroke(YELLOW, SUPERSOLID); 402 | } 403 | curColor++; 404 | if(curColor == 4) 405 | { 406 | curColor = 0; 407 | } 408 | } 409 | } 410 | } 411 | if(dualExtrusionColoring) 412 | { 413 | if(ls.getExtruding()) 414 | { 415 | if(ls.getToolhead() == 0) 416 | { 417 | stroke(BLUE, curTransparency); 418 | } 419 | if(ls.getToolhead() == 1) 420 | { 421 | stroke(GREEN, curTransparency); 422 | } 423 | } 424 | } 425 | 426 | if(!is2D || (ls.getLayer() == maxLayer)) 427 | { 428 | points = ls.getPoints(); 429 | 430 | //vertex(points[0],points[1],points[2],points[3], points[4], points[5]); 431 | vertex(points[0],points[1],points[2]); 432 | vertex(points[3],points[4],points[5]); 433 | } 434 | } endShape(); 435 | if((curLayer != maxLayer) && is2D) 436 | { 437 | cam.setDistance(cam.getDistance() + (maxLayer - curLayer)*.3,0); 438 | } 439 | curLayer = maxLayer; 440 | } 441 | popMatrix(); 442 | // makes the gui stay on top of elements 443 | // drawn before. 444 | hint(DISABLE_DEPTH_TEST); 445 | 446 | gui(); 447 | } 448 | 449 | private void gui() { 450 | noSmooth(); 451 | //currCameraMatrix = new PMatrix3D(g3.camera); 452 | //camera(); 453 | cam.beginHUD(); 454 | controlP5.draw(); 455 | cam.endHUD(); 456 | //g3.camera = currCameraMatrix; 457 | } 458 | void selectFile() { 459 | 460 | try 461 | { 462 | 463 | SwingUtilities.invokeLater(new Runnable() { 464 | public void run() 465 | { 466 | JFileChooser fc = new JFileChooser("."); 467 | FileFilter gcodeFilter = new FileNameExtensionFilter("Gcode file", "gcode", "ngc"); 468 | fc.setDialogTitle("Choose a file..."); 469 | fc.setFileFilter(gcodeFilter); 470 | 471 | int returned = fc.showOpenDialog(frame); 472 | if (returned == JFileChooser.APPROVE_OPTION) 473 | { 474 | isDrawable = false; 475 | File file = fc.getSelectedFile(); 476 | gCode = (String)file.getPath(); 477 | println(gCode); 478 | generateObject(); 479 | 480 | } 481 | } 482 | }); 483 | } 484 | catch(Exception e) 485 | { 486 | e.printStackTrace(); 487 | } 488 | 489 | } 490 | public void mouseMoved() { 491 | if(mouseX < 35 || (mouseY < 50 && mouseX > (width - 130)) || is2D) 492 | { 493 | cam.setActive(false); 494 | } 495 | else 496 | { 497 | cam.setActive(true); 498 | } 499 | } 500 | 501 | public ArrayList readFiletoArrayList(String s) { 502 | ArrayList vect; 503 | String lines[] = loadStrings(s); 504 | vect = new ArrayList(Arrays.asList(lines)); 505 | return vect; 506 | } 507 | public void mousePressed() { 508 | redraw(); 509 | } 510 | -------------------------------------------------------------------------------- /code/GcodeViewParse.java: -------------------------------------------------------------------------------- 1 | import java.util.List; 2 | import java.util.ArrayList; 3 | import java.util.Arrays; 4 | 5 | import javax.vecmath.Point3f; 6 | 7 | 8 | public class GcodeViewParse { 9 | private static boolean debugVals = false; 10 | 11 | public GcodeViewParse() 12 | { 13 | 14 | } 15 | public ArrayList toObj(ArrayList gcode) 16 | { 17 | float speed = 2; //DEFAULTS to 2 18 | Point3f lastPoint = null; 19 | Point3f curPoint = null; 20 | int curLayer = 0; 21 | int curToolhead = 0; 22 | float parsedX, parsedY, parsedZ, parsedF; 23 | float tolerance = .0002f; 24 | ArrayList lines = new ArrayList(); 25 | float[] lastCoord = { 0.0f, 0.0f, 0.0f}; 26 | boolean currentExtruding = false; 27 | for(String s : gcode) 28 | { 29 | if(s.matches(".*M101.*")) 30 | { 31 | currentExtruding = true; 32 | } 33 | if(s.matches(".*M103.*")) 34 | { 35 | currentExtruding = false; 36 | } 37 | if(s.matches(".*T0.*")) 38 | { 39 | curToolhead = 0; 40 | } 41 | if(s.matches(".*T1.*")) 42 | { 43 | curToolhead = 1; 44 | } 45 | if (s.matches(".*G1.*")) 46 | { 47 | String[] sarr = s.split(" "); 48 | parsedX = parseCoord(sarr, 'X'); 49 | parsedY = parseCoord(sarr, 'Y'); 50 | parsedZ = parseCoord(sarr, 'Z'); 51 | parsedF = parseCoord(sarr, 'F'); 52 | 53 | //System.out.println(Arrays.toString(sarr)); 54 | if(!Float.isNaN(parsedX)) 55 | { 56 | lastCoord[0] = parsedX; 57 | } 58 | if(!Float.isNaN(parsedY)) 59 | { 60 | lastCoord[1] = parsedY; 61 | } 62 | if(!Float.isNaN(parsedZ)) 63 | { 64 | if (!(Math.abs(parsedZ - lastCoord[2]) <= tolerance)) 65 | { 66 | curLayer++; 67 | } 68 | lastCoord[2] = parsedZ; 69 | } 70 | if(!Float.isNaN(parsedF)) 71 | { 72 | speed = parsedF; 73 | } 74 | if(!(Float.isNaN(lastCoord [0]) || Float.isNaN(lastCoord [1]) || Float.isNaN(lastCoord [2]))) 75 | { 76 | if(debugVals) 77 | { 78 | System.out.println(lastCoord[0] + "," + lastCoord [1] + "," + lastCoord[2] + ", speed =" + speed + 79 | ", layer=" + curLayer); 80 | } 81 | curPoint = new Point3f(lastCoord[0], lastCoord[1], lastCoord[2]); 82 | 83 | if(lastPoint != null) 84 | { 85 | 86 | lines.add(new LineSegment(lastPoint, curPoint, curLayer, speed, curToolhead, currentExtruding)); 87 | } 88 | lastPoint = curPoint; 89 | } 90 | } 91 | 92 | } 93 | return lines; 94 | 95 | } 96 | 97 | 98 | private float parseCoord(String[] sarr, char c) 99 | { 100 | for(String t : sarr) 101 | { 102 | if(t.matches("\\s*[" + c + "]\\s*-*[\\d|\\.]+")) 103 | { 104 | //System.out.println("te : " + t); 105 | return Float.parseFloat(t.substring(1,t.length())); 106 | } 107 | } 108 | return Float.NaN; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /code/LineSegment.java: -------------------------------------------------------------------------------- 1 | import javax.vecmath.Point3f; 2 | 3 | public class LineSegment { 4 | 5 | private int layer; 6 | private int toolhead = 0; //DEFAULT TOOLHEAD ASSUMED TO BE 0! 7 | private float speed; 8 | private Point3f first, second; 9 | private boolean isExtruding; 10 | 11 | public LineSegment (Point3f a,Point3f b, int layernum, float speedz) 12 | { 13 | first = a; 14 | second = b; 15 | layer = layernum; 16 | speed = speedz; 17 | } 18 | public LineSegment (Point3f a,Point3f b, int layernum, float speedz, boolean extrudz) 19 | { 20 | first = a; 21 | second = b; 22 | layer = layernum; 23 | speed = speedz; 24 | isExtruding = extrudz; 25 | } 26 | public LineSegment(float x1, float y1, float z1, float x2, float y2, float z2, int layernum, float speedz) 27 | { 28 | first = new Point3f(x1, y1, z1); 29 | second = new Point3f(x2, y2, z2); 30 | layernum = layer; 31 | speed = speedz; 32 | } 33 | public LineSegment (Point3f a,Point3f b, int layernum, float speedz, int toolheadz) 34 | { 35 | first = a; 36 | second = b; 37 | layer = layernum; 38 | speed = speedz; 39 | toolhead = toolheadz; 40 | } 41 | public LineSegment(float x1, float y1, float z1, float x2, float y2, float z2, int layernum, float speedz, int toolheadz) 42 | { 43 | first = new Point3f(x1, y1, z1); 44 | second = new Point3f(x2, y2, z2); 45 | layernum = layer; 46 | speed = speedz; 47 | toolhead = toolheadz; 48 | } 49 | public LineSegment (Point3f a,Point3f b, int layernum, float speedz, int toolheadz, boolean extrudz) 50 | { 51 | first = a; 52 | second = b; 53 | layer = layernum; 54 | speed = speedz; 55 | toolhead = toolheadz; 56 | isExtruding = extrudz; 57 | } 58 | public LineSegment(float x1, float y1, float z1, float x2, float y2, float z2, int layernum, float speedz, int toolheadz, boolean extrudz) 59 | { 60 | first = new Point3f(x1, y1, z1); 61 | second = new Point3f(x2, y2, z2); 62 | layernum = layer; 63 | speed = speedz; 64 | toolhead = toolheadz; 65 | isExtruding = extrudz; 66 | 67 | } 68 | public Point3f[] getPointArray() 69 | { 70 | Point3f[] pointarr = { first, second }; 71 | return pointarr; 72 | } 73 | public float[] getPoints() 74 | { 75 | float[] points = {first.x, first.y, first.z , second.x, second.y, second.z }; 76 | return points; 77 | } 78 | public int getToolhead() 79 | { 80 | return toolhead; 81 | } 82 | public float getSpeed() 83 | { 84 | return speed; 85 | } 86 | public int getLayer() 87 | { 88 | return layer; 89 | } 90 | public boolean getExtruding() 91 | { 92 | return isExtruding; 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /code/vecmath.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmsl1993/ProcessingGcodeViewer/4fd623a40d03565eea7b8214a56b60521b226b73/code/vecmath.jar --------------------------------------------------------------------------------