Advertisement
Morbo

svg2plottertransformer

Apr 1st, 2012
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 9.79 KB | None | 0 0
  1. //svg2plottertransformer
  2.  
  3. package com.tinkerlog.kritzler;
  4.  
  5.  
  6. import java.util.ArrayList;
  7. import java.util.Collections;
  8. import java.util.List;
  9.  
  10. import processing.core.PApplet;
  11. import processing.core.PMatrix3D;
  12. import processing.core.PShape;
  13.  
  14. public class SVG2PlotterTransformer {
  15.  
  16.   private static final float MAX_DISTANCE = 300.0F;
  17.  
  18.   private float minX = Float.MAX_VALUE;
  19.   private float maxX = Float.MIN_VALUE;
  20.   private float minY = Float.MAX_VALUE;
  21.   private float maxY = Float.MIN_VALUE;
  22.  
  23.   private int bezierDetail = 20;
  24.   private float prev[];
  25.   private PMatrix3D draw;
  26.   private PMatrix3D bezierBasisMatrix = new PMatrix3D(
  27.       -1,  3, -3,  1,
  28.       3, -6,  3,  0,
  29.       -3,  3,  0,  0,
  30.       1,  0,  0,  0);
  31.   private List<float[]> lines;
  32.   private List<Instruction> instructions;
  33.  
  34.  
  35.   public SVG2PlotterTransformer() {
  36.     draw = new PMatrix3D();
  37.     splineForward(bezierDetail, draw);
  38.     draw.apply(bezierBasisMatrix);
  39.     lines = new ArrayList<float[]>(100);
  40.     instructions = new ArrayList<Instruction>();
  41.     prev = new float[2];
  42.   }
  43.  
  44.   public List<float[]> getLines() {
  45.     return lines;
  46.   }
  47.  
  48.   public List<Instruction> getInstructions() {
  49.     return instructions;
  50.   }
  51.  
  52.   public float getMinX() {
  53.     return minX;
  54.   }
  55.  
  56.   public float getMaxX() {
  57.     return maxX;
  58.   }
  59.  
  60.   public float getMinY() {
  61.     return minY;
  62.   }
  63.  
  64.   public float getMaxY() {
  65.     return maxY;
  66.   }
  67.    
  68.   public void analyzeShape(PShape shape) {
  69.     if (shape.getFamily() == PShape.GROUP) {
  70.       for (int i = 0; i < shape.getChildCount(); i++) {
  71.         PShape child = shape.getChild(i);
  72.         analyzeShape(child);
  73.       }
  74.     }
  75.     else if (shape.getFamily() == PShape.PATH) {
  76.       analyzePath(shape);
  77.     }
  78.     else {
  79.       System.out.println("unknow type: " + shape.getFamily());
  80.     }
  81.   }
  82.  
  83.   public void analyzePath(PShape s) {
  84.     int i = 0;
  85.     boolean first = true;
  86.     for (int j = 0; j < s.getVertexCodeCount(); j++) {
  87.       switch (s.getVertexCode(j)) {
  88.       case PShape.VERTEX:        
  89.         float p1[];
  90.         p1 = s.getVertex(i);
  91.         checkPoint(p1[0], p1[1]);
  92.         if (first) {
  93.           first = false;
  94.           instructions.add(new Instruction(Instruction.MOVE_ABS, p1[0], p1[1]));
  95.         }
  96.         else {
  97.           addLine(prev[0], prev[1], p1[0], p1[1]);
  98.           instructions.add(new Instruction(Instruction.LINE_ABS, p1[0], p1[1]));
  99.         }
  100.         prev = p1;
  101.         i++;
  102.         break;
  103.       case PShape.BEZIER_VERTEX:
  104.         float[] c1, c2, p2;
  105.         c1 = s.getVertex(i);
  106.         c2 = s.getVertex(i+1);
  107.         p2 = s.getVertex(i+2);
  108.         bezierVertex(c1[0], c1[1], c2[0], c2[1], p2[0], p2[1]);
  109.         checkPoint(p2[0], p2[1]);
  110.         i += 3;
  111.         break;
  112.       case PShape.BREAK:
  113.         first = true;
  114.         break;
  115.       default:
  116.         System.out.println("unknow code: " + s.getVertexCode(j));
  117.       }
  118.     }
  119.   }
  120.  
  121.   private void bezierVertex(float x2, float y2, float x3, float y3, float x4, float y4) {
  122.  
  123.     float x1 = prev[0];
  124.     float y1 = prev[1];
  125.  
  126.     float xplot1 = draw.m10*x1 + draw.m11*x2 + draw.m12*x3 + draw.m13*x4;
  127.     float xplot2 = draw.m20*x1 + draw.m21*x2 + draw.m22*x3 + draw.m23*x4;
  128.     float xplot3 = draw.m30*x1 + draw.m31*x2 + draw.m32*x3 + draw.m33*x4;
  129.  
  130.     float yplot1 = draw.m10*y1 + draw.m11*y2 + draw.m12*y3 + draw.m13*y4;
  131.     float yplot2 = draw.m20*y1 + draw.m21*y2 + draw.m22*y3 + draw.m23*y4;
  132.     float yplot3 = draw.m30*y1 + draw.m31*y2 + draw.m32*y3 + draw.m33*y4;
  133.  
  134.     float oldx = x1;
  135.     float oldy = y1;
  136.     for (int j = 0; j < bezierDetail; j++) {
  137.       x1 += xplot1; xplot1 += xplot2; xplot2 += xplot3;
  138.       y1 += yplot1; yplot1 += yplot2; yplot2 += yplot3;
  139.       addLine(oldx, oldy, x1, y1);
  140.       instructions.add(new Instruction(Instruction.LINE_ABS, x1, y1));
  141.       oldx = x1;
  142.       oldy = y1;
  143.     }
  144.     prev[0] = x4;
  145.     prev[1] = y4;    
  146.   }  
  147.  
  148.   private void addLine(float x1, float y1, float x2, float y2) {
  149.     float[] line = new float[4];
  150.     line[0] = x1+20;
  151.     line[1] = y1+20;
  152.     line[2] = x2+20;
  153.     line[3] = y2+20;
  154.     lines.add(line);    
  155.   }
  156.  
  157.   private void checkPoint(float x, float y) {    
  158.     if (x < minX) {
  159.       minX = x;      
  160.     }
  161.     if (x > maxX) {
  162.       maxX = x;
  163.     }
  164.     if (y < minY) {
  165.       minY = y;
  166.     }
  167.     if (y > maxY) {
  168.       maxY = y;
  169.     }
  170.   }
  171.  
  172.  
  173.   public List<float[]> getPatternLines(List<float[]> lines, List<Instruction> instructions) {
  174.    
  175.     List<float[]> cutLines = new ArrayList<float[]>();
  176.     for (int i = 0; i < 300; i++) {
  177.       float[] l = new float[4];
  178.       l[0] = 0F;
  179.       l[1] = i*45F;
  180.       l[2] = i*45F;
  181.       l[3] = 0F;
  182.       cutLines.add(l);
  183.     }
  184.    
  185.     List<float[]> patternLines = intersectShapeLines(lines, cutLines);
  186.    
  187.     List<float[]> shortPatternLines = makeShortLines(patternLines);
  188.    
  189.     System.out.println("patternLines: " + patternLines.size());
  190.     for (int i = 0; i < shortPatternLines.size(); i++) {
  191.       float[] l = shortPatternLines.get(i);
  192.       // TODO optimize
  193.       instructions.add(new Instruction(Instruction.MOVE_ABS, l[0], l[1]));
  194.       instructions.add(new Instruction(Instruction.LINE_ABS, l[2], l[3]));
  195.     }
  196.     System.out.println("shortPatternLines: " + shortPatternLines.size());
  197.    
  198.     return shortPatternLines;    
  199.   }
  200.    
  201.   public List<float[]> intersectShapeLines(List<float[]> shape, List<float[]> lines) {
  202.     List<float[]> result = new ArrayList<float[]>();
  203.     for (int i = 0; i < lines.size(); i++) {
  204.       float[] line = lines.get(i);
  205.      
  206.       List<Point> intersections = intersectShapeLine(shape, line);
  207.      
  208.       if (intersections.size() > 0) {
  209.         if (intersections.size() % 2 != 0) {
  210.           // jitter lines if odd number of intersections
  211.           line[0] += Math.random();
  212.           line[2] += Math.random();
  213.           intersections = intersectShapeLine(shape, line);
  214.           if (intersections.size() % 2 != 0) {
  215.             System.out.println("--> intersections: " + intersections.size());
  216.           }
  217.         }
  218.         int k = 0;
  219.         while (k+1 < intersections.size()) {
  220.           Point p1 = intersections.get(k);
  221.           Point p2 = intersections.get(k+1);
  222.           float d = p1.distance(p2);
  223.           if (d > 5) {
  224.             float[] l = {p1.x, p1.y, p2.x, p2.y};
  225.             result.add(l);    
  226.           }
  227.           k += 2;
  228.         }
  229.       }
  230.     }
  231.     return result;    
  232.   }
  233.  
  234.   public List<Point> intersectShapeLine(List<float[]> shape, float[] line) {
  235.     List<Point> intersections = new ArrayList<Point>();
  236.     for (int j = 0; j < shape.size(); j++) {
  237.       float[] shapeLine = shape.get(j);
  238.       Point p = intersectLine(
  239.           line[0], line[1], line[2], line[3],
  240.           shapeLine[0], shapeLine[1],shapeLine[2],shapeLine[3]);
  241.       if (p != null) {
  242.         intersections.add(p);
  243.       }
  244.     }
  245.     Collections.sort(intersections);
  246.     return intersections;
  247.   }
  248.  
  249.   private List<float[]> makeShortLines(List<float[]> lines) {
  250.     List<float[]> newLines = new ArrayList<float[]>();
  251.     for (int i = 0; i < lines.size(); i++) {
  252.       float[] line = lines.get(i);      
  253.       float x1 = line[2];
  254.       float y1 = line[3];
  255.       float x2 = line[0];
  256.       float y2 = line[1];
  257. //      float y2y1 = line[1] - line[3];
  258. //      float x2x1 = line[0] - line[2];
  259.       float y2y1 = y1 - y2;
  260.       float x2x1 = x1 - x2;
  261.       float distance = (float)Math.sqrt(y2y1*y2y1 + x2x1*x2x1);
  262.       if (distance > MAX_DISTANCE) {
  263.         // System.out.println("distance: " + distance);
  264.         float m = y2y1 / x2x1;
  265.         float n = y1 - m * x1;
  266.         float dc = distance / MAX_DISTANCE;
  267.         //System.out.println("  dc: " + dc);
  268.         float dx = x2x1 / dc;
  269.         //System.out.println("  dx: " + dx);
  270. //        float x2 = line[2];
  271. //        float x1 = line[0];
  272. //        float y2 = line[3];
  273. //        float y1 = 0.0F;
  274.         while (x1 > x2) {
  275.           float[] newLine = new float[4];
  276.           newLine[0] = x2;
  277.           newLine[1] = y2;
  278.           //System.out.println("  x2, x1 " + x2 + ", " + x1);
  279.           x2 = x2 + dx;
  280.           if (x2 > x1) {
  281.             x2 = x1;
  282.           }
  283.           newLine[2] = x2;
  284.           newLine[3] = m * x2 + n;
  285.           y2 = newLine[3];
  286.           newLines.add(newLine);
  287.         }        
  288.       }
  289.       else {
  290.         newLines.add(line);
  291.       }
  292.      
  293.     }
  294.     return newLines;
  295.   }
  296.  
  297.  
  298.   public Point intersectLine(float p0x, float p0y, float p1x, float p1y,
  299.       float p2x, float p2y, float p3x, float p3y) {
  300.    
  301.     float x, y;
  302.    
  303.     float d1x = p1x - p0x;
  304.     float d2x = p3x - p2x;
  305.     float d1y = p1y - p0y;
  306.     float d2y = p3y - p2y;
  307.    
  308.     float s = (-d1y * (p0x - p2x) + d1x * (p0y - p2y)) / (-d2x * d1y + d1x * d2y);
  309.     float t = ( d2x * (p0y - p2y) - d2y * (p0x - p2x)) / (-d2x * d1y + d1x * d2y);
  310.  
  311.     if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
  312.       // Collision detected
  313.       x = p0x + (t * d1x);
  314.       y = p0y + (t * d1y);
  315.       return new Point(x, y);
  316.     }    
  317.     return null;      
  318.   }
  319.  
  320.   private class Point implements Comparable<Point> {
  321.    
  322.     public float x;
  323.     public float y;
  324.    
  325.     public Point(float x, float y) {
  326.       this.x = x;
  327.       this.y = y;
  328.     }
  329.    
  330.     public float distance(Point p) {
  331.       float dx = x - p.x;
  332.       float dy = y - p.y;
  333.       return PApplet.sqrt(dx*dx + dy*dy);
  334.     }
  335.  
  336.     @Override
  337.     public int compareTo(Point other) {
  338.       return (x < other.x) ? -1 : (x == other.x) ? 0 : 1;
  339.     }
  340.    
  341.   }
  342.  
  343.  
  344.  
  345.  
  346.   private void splineForward(int segments, PMatrix3D matrix) {
  347.     float f  = 1.0f / segments;
  348.     float ff = f * f;
  349.     float fff = ff * f;
  350.     matrix.set(0,     0,    0, 1,
  351.                fff,   ff,   f, 0,
  352.                6*fff, 2*ff, 0, 0,
  353.                6*fff, 0,    0, 0);
  354.   }
  355.      
  356. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement