diff --git a/src/com/t_oster/liblasercut/drivers/Dummy.java b/src/com/t_oster/liblasercut/drivers/Dummy.java index 8c27a0d56a9a3adec462c60f3abadb26ac049107..e0a3c0d986362571562e1882ae619e515f0e5017 100644 --- a/src/com/t_oster/liblasercut/drivers/Dummy.java +++ b/src/com/t_oster/liblasercut/drivers/Dummy.java @@ -21,6 +21,12 @@ package com.t_oster.liblasercut.drivers; import com.t_oster.liblasercut.*; import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.util.*; /** @@ -33,26 +39,204 @@ public class Dummy extends LaserCutter { private static final String SETTING_BEDWIDTH = "Laserbed width"; private static final String SETTING_BEDHEIGHT = "Laserbed height"; private static final String SETTING_RUNTIME = "Fake estimated run-time in seconds (-1 to disable)"; + private static final String SETTING_SVG_OUTDIR = "SVG Debug output directory (set empty to disable)"; + + /** + * SVG output creator, mostly for testing vector-sorting + */ + class SVGWriter { + private double xPrev,xNow,yPrev,yNow; + private StringBuilder svg = new StringBuilder(); + private boolean vectorPathActive=false; + private boolean partActive=false; + private int idCounter=0; + private int partCounter=0; + private LaserCutter cutter; + private double dpi; + + + public SVGWriter(LaserCutter cutter) { + this.cutter = cutter; + } + + /** + * start a new JobPart + * @param title some string that will be included in the group ID + * @param dpi + */ + public void startPart(String title, double dpi) { + endPart(); + partCounter += 1; + this.dpi=dpi; + this.partActive=true; + svg.append("<g style=\"fill:none;stroke:#000000;stroke-width:0.1mm;\" id=\""); + svg.append("visicut-part").append(partCounter).append("-"); + svg.append(title.replaceAll("[^a-zA-Z0-9]","_")); + svg.append("\">\n"); + } + + /** + * end a JobPart + */ + public void endPart() { + moveTo(0,0); // end path + if (partActive) { + partActive=false; + svg.append("</g>\n"); + } + } + + private void setLocation(int x, int y) { + xPrev=xNow; + yPrev=yNow; + double factor = 25.4/dpi; // convert units to millimeters + xNow=x*factor; + yNow=y*factor; + } + + /** + * move to somewhere with laser off + * @param x + * @param y + */ + void moveTo(int x, int y) { + setLocation(x,y); + if (vectorPathActive) { + // end the previous path + svg.append("\"/>\n"); + vectorPathActive=false; + } + } + + /** + * move to somewhere with laser on + * @param x + * @param y + */ + void lineTo(int x, int y) { + setLocation(x,y); + if (!partActive) { + throw new RuntimeException("lineTo called outside of a part!"); + } + if (!vectorPathActive) { + // start a new path + vectorPathActive=true; + svg.append("<path id=\"visicut-").append(idCounter).append("\" d=\"M "); + idCounter += 1; + svg.append(xPrev).append(",").append(yPrev).append(" "); + } + svg.append(xNow).append(",").append(yNow).append(" "); + } + + /** + * generate SVG output string and reset everything (delete all path data) + * @return + */ + private String getSVG() { + endPart(); + svg.insert(0,"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?> \n" + + "<!-- Created by VisiCut Debug output -->\n" + + "<svg xmlns:svg=\"http://www.w3.org/2000/svg\" " + + "xmlns=\"http://www.w3.org/2000/svg\" " + + "width=\"" + cutter.getBedWidth() + "mm\" " + + "height=\"" + cutter.getBedHeight() + "mm\" " + + "viewBox=\"0 0 " + cutter.getBedWidth() + " " + cutter.getBedHeight() + "\" " + + "version=\"1.1\" id=\"svg\"> \n"); + svg.append("</svg>\n"); + String result=svg.toString(); + svg = new StringBuilder(); + idCounter=0; + return result; + } + + /** + * store a String into a file + * @param path the filename + * @param str the content to be stored + */ + private void storeString(String path, String str) { + try { + FileWriter f = new FileWriter(path); + BufferedWriter b = new BufferedWriter(f); + b.write(str); + b.close(); + } catch (Exception e) { + System.out.println("Could not write debug SVG: Exception: " + e); + } + } + + /** + * store XHTML viewer to file + * @param path + * @param svgString + */ + void storeXHTML(String path, String svgString) { + BufferedReader br = null; + StringBuilder xhtml = new StringBuilder(); + try { + InputStream stream = new Dummy().getClass().getResourceAsStream("resources/visicut-svg-output-viewer.xhtml"); + StringBuilder s = new StringBuilder(); + br = new BufferedReader(new InputStreamReader(stream, "UTF-8")); + String line=""; + while ((line=br.readLine()) != null) { + if (line.contains("<!-- REPLACE THIS WITH SVG -->")) { + // insert svg, but skip first line with <?xml... + line=svgString.substring(svgString.indexOf("\n")); + } + xhtml.append(line).append("\n"); + } + storeString(path, xhtml.toString()); + } catch (Exception e) { + System.out.println("could not store debug XHTML: " + e); + } finally { + try { + br.close(); + } catch (IOException ex) { + System.out.println("could not close bufferedWriter when storing debug XHTML"); + } + } + } + + void store(String directory) { + if (directory == null || directory.isEmpty()) { + System.out.println("Not writing debug SVG - no output directory set (edit lasercutter settings to change)"); + } else { + String pathSVG=directory + "/visicut-debug.svg"; + System.out.println("storing SVG debug output to "+pathSVG); + String svgString=getSVG(); + storeString(pathSVG,svgString); + String pathXHTML=directory + "/visicut-svg-output-viewer.xhtml"; + System.out.println("storing SVG debug output (XHTML viewer) to "+pathXHTML); + storeXHTML(pathXHTML, svgString); + } + } + + } + @Override public String getModelName() { return "Dummy"; } + + @Override public void sendJob(LaserJob job, ProgressListener pl) throws IllegalJobException, Exception { pl.progressChanged(this, 0); - + BufferedOutputStream out; pl.taskChanged(this, "checking job"); checkJob(job); job.applyStartPoint(); pl.taskChanged(this, "sending"); pl.taskChanged(this, "sent."); + SVGWriter svg = new SVGWriter(this); // SVG debug output System.out.println("dummy-driver got LaserJob: "); //Â TODOÂ don't just print the parts and settins, but also the commands //Â TODO if you have too much time, also implement some preview output (svg animation???) - would be nice for testing optimisations for (JobPart p : job.getParts()) { + svg.startPart(p.getClass().getSimpleName(), p.getDPI()); if (p instanceof VectorPart) { System.out.println("VectorPart"); @@ -60,16 +244,25 @@ public class Dummy extends LaserCutter { { if (cmd.getType() == VectorCommand.CmdType.SETPROPERTY) { + if (!(cmd.getProperty() instanceof PowerSpeedFocusFrequencyProperty)) { throw new IllegalJobException("This driver expects Power,Speed,Frequency and Focus as settings"); } System.out.println(((PowerSpeedFocusFrequencyProperty) cmd.getProperty()).toString()); + } else if (cmd.getType() == VectorCommand.CmdType.LINETO) { + System.out.println("LINETO \t" + cmd.getX() + ", \t" + cmd.getY()); + svg.lineTo(cmd.getX(),cmd.getY()); + } else if (cmd.getType() == VectorCommand.CmdType.MOVETO) { + System.out.println("MOVETO \t" + cmd.getX() + ", \t" + cmd.getY()); + svg.moveTo(cmd.getX(),cmd.getY()); } } + } if (p instanceof RasterPart) { + // TODO add raster output for SVG debug output RasterPart rp = ((RasterPart) p); if (rp.getLaserProperty() != null && !(rp.getLaserProperty() instanceof PowerSpeedFocusProperty)) { @@ -89,6 +282,7 @@ public class Dummy extends LaserCutter { } } System.out.println("end of job."); + svg.store(svgOutdir); pl.progressChanged(this, 100); } @@ -161,10 +355,14 @@ public class Dummy extends LaserCutter { public void setBedHeight(double bedHeight) { this.bedHeight = bedHeight; } + + public String svgOutdir=""; + private static String[] settingAttributes = new String[]{ SETTING_BEDWIDTH, SETTING_BEDHEIGHT, - SETTING_RUNTIME + SETTING_RUNTIME, + SETTING_SVG_OUTDIR }; @Override @@ -180,6 +378,8 @@ public class Dummy extends LaserCutter { return this.getBedHeight(); } else if (SETTING_RUNTIME.equals(attribute)) { return this.fakeRunTime; + } else if (SETTING_SVG_OUTDIR.equals(attribute)) { + return this.svgOutdir; } return null; } @@ -192,6 +392,8 @@ public class Dummy extends LaserCutter { this.setBedHeight((Double) value); } else if (SETTING_RUNTIME.equals(attribute)) { this.fakeRunTime=Integer.parseInt(value.toString()); + } else if (SETTING_SVG_OUTDIR.equals(attribute)) { + this.svgOutdir=value.toString(); } } diff --git a/src/com/t_oster/liblasercut/drivers/resources/visicut-svg-output-viewer.xhtml b/src/com/t_oster/liblasercut/drivers/resources/visicut-svg-output-viewer.xhtml new file mode 100644 index 0000000000000000000000000000000000000000..938338cecc7a9e9e4cc25ddebd5e4919dc88b952 --- /dev/null +++ b/src/com/t_oster/liblasercut/drivers/resources/visicut-svg-output-viewer.xhtml @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html +PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" +xmlns:svg="http://www.w3.org/2000/svg" +xmlns:xlink="http://www.w3.org/1999/xlink"> +<head> +<title>VisiCut SVG debug view</title> +</head> +<style> +.done{stroke:black;} +.todo{stroke:grey; fill:none;} +</style> +<script> +<![CDATA[ +var maximum=0; +function load(n) { + // get maximum + var i=0; + while (true) { + var obj=document.getElementById('visicut-'+i); + if (obj==null) { + // end of elements reached + break; + } + i++; + maximum=i; + } + document.getElementById('slider').max=maximum; +} +function showUntil(n) { + for (var i=0; i<n; i++) { + document.getElementById('visicut-'+i).setAttribute('class','done'); + } + var i=n; + while (true) { + var obj=document.getElementById('visicut-'+i); + if (obj==null) { + // end of elements reached + break; + } + obj.setAttribute('class','todo'); + i++; + } +} +]]> +</script> +<body onload="load()"> + +<h1>VisiCut debug output</h1> +<div style="display:block; width:100%;"> + Slide to see individual steps. Please use this with Chrome or another browser that supports <input type="range"> (not Firefox).<br/> +Start <input id="slider" type="range" value="0" min="0" max="0" onchange="showUntil(this.value)" style="width:60%"/> End +</div> + + +<!-- REPLACE THIS WITH SVG --> + +</body> +</html> \ No newline at end of file