CaptainSpaceCat

eBeam - STLConverter

Jul 13th, 2016
87
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import java.awt.image.*;
  2. import java.awt.Color;
  3. import java.awt.*;
  4. import java.io.*;
  5. import javax.imageio.*;
  6. import javax.swing.SwingUtilities;
  7. import javax.swing.filechooser.*;
  8. import javax.swing.*;
  9. import java.util.ArrayList;
  10.  
  11. /* This class does the heavy lifting for
  12.  * the conversion of a correctly formatted image
  13.  * into an STL file.
  14.  * */
  15.  
  16. public class STLConverter {
  17.  
  18.   public static final int COLOR_BLACK = -16777216;
  19.   public static final int COLOR_WHITE = -1;
  20.   BufferedImage img;
  21.   BufferedImage template;
  22.   int w, h;
  23.   int[] center;
  24.   int[][] crossPoints;
  25.  
  26.   public STLConverter() {            //   01
  27.   }                                  //45 [] 67
  28.                                      //   23
  29.   public void setCenterInfo(int[] c, int[][] cPoints) {
  30.     center = c;
  31.     crossPoints = cPoints;
  32.   }
  33.  
  34.   public String convertImage(BufferedImage i, int scale, float pxcm) {
  35.     w = i.getWidth();
  36.     h = i.getHeight();
  37.     img = i;
  38.     PolyOutline[] outlines = generateNodeMap(8, false);
  39.     outlines[0].optimize(outlines[1].optimize(500, crossPoints));
  40.     Mesh mesh = convertPolyToMesh(outlines);
  41.     flipMesh(mesh);
  42.     scaleMeshVertices(mesh, pxcm, scale, 15f);
  43.     return writeSTL(mesh);
  44.   }
  45.  
  46.   public void setImageTemplate(BufferedImage i) {
  47.     template = i;
  48.   }
  49.  
  50.   public PolyOutline[] generateNodeMap(int speckSize, boolean single) {
  51.     boolean broken = false;
  52.     ArrayList<PolyOutline> maps = new ArrayList<PolyOutline>();
  53.     for (int y = 1; y < h-1; y++) {
  54.       for (int x = 1; x < w-1; x++) {
  55.         //System.out.println("----====" + x + ":" + y);
  56.         if (img.getRGB(x, y) == COLOR_BLACK) {
  57.           PolyOutline poly = new PolyOutline(w, h);
  58.           int[] startPos = {x, y};
  59.           int[] currentPos = {x, y};
  60.           poly.add(currentPos);
  61.           //System.out.println(currentPos[0] + ":" + currentPos[1]);
  62.           currentPos = trace(x, y, null, poly);
  63.           while (currentPos[0] != startPos[0] || currentPos[1] != startPos[1]) {
  64.             poly.add(currentPos);
  65.             //System.out.println(currentPos[0] + ":" + currentPos[1]);
  66.             currentPos = trace(currentPos[0], currentPos[1], poly.getPrevPos(), poly);
  67.           }
  68.           invertImage(poly.edgeGrid);
  69.           if (poly.nodeMap.size() > speckSize) {
  70.             maps.add(poly);
  71.           }
  72.           if (single) {
  73.             broken = true;
  74.             break;
  75.           }
  76.         }
  77.       }
  78.       if (broken) {
  79.         break;
  80.       }
  81.     }
  82.     return maps.toArray(new PolyOutline[maps.size()]);
  83.   }
  84.  
  85.   int[] trace(int x, int y, int[] prevPos, PolyOutline p) {
  86.     int t = 0;
  87.     if (img.getRGB(x-1, y-1) == COLOR_BLACK) {
  88.       t += 1;
  89.     }
  90.     if (img.getRGB(x, y-1) == COLOR_BLACK) {
  91.       t += 2;
  92.     }
  93.     if (img.getRGB(x-1, y) == COLOR_BLACK) {
  94.       t += 4;
  95.     }
  96.     if (img.getRGB(x, y) == COLOR_BLACK) {
  97.       t += 8;
  98.     }
  99.    
  100.     int[][] coords = new int[0][0];
  101.    
  102.     if (t == 0) {
  103.       System.err.println("Tracing failed: No black pixels in range");
  104.     } else if (t == 1 || t == 14) {
  105.       coords = new int[][] {{-1, 0}, {0, -1}};
  106.     } else if (t == 2 || t == 13) {
  107.       coords = new int[][] {{1, 0}, {0, -1}};
  108.     } else if (t == 4 || t == 11) {
  109.       coords = new int[][] {{-1, 0}, {0, 1}};   //put this in a table and just index it
  110.     } else if (t == 8 || t == 7) {           //do it later
  111.       coords = new int[][] {{1, 0}, {0, 1}}; //dont forget >:C
  112.     } else if (t == 3 || t == 12) {
  113.       coords = new int[][] {{-1, 0}, {1, 0}};
  114.     } else if (t == 5 || t == 10) {
  115.       coords = new int[][] {{0, -1}, {0, 1}};
  116.     } else {
  117.       System.err.println("Tracing failed: Unexpected case");
  118.     }
  119.     int choice = 0;
  120.     if (prevPos != null) {
  121.       //System.out.println("Prev=" + prevPos[0] + ":" + prevPos[1]);
  122.       if (prevPos[0] == coords[0][0]+x && prevPos[1] == coords[0][1]+y) {
  123.         choice = 1;
  124.       }
  125.     }
  126.     if (coords[choice][1] == -1) {
  127.       p.addEdge(x, y-1);
  128.     } if (coords[choice][1] == 1) {
  129.       p.addEdge(x, y);
  130.     }
  131.     int[] result = {coords[choice][0] + x, coords[choice][1] + y};
  132.     return result;
  133.   }
  134.  
  135.   void invertImage(boolean[][] n) {
  136.     for (int y = 0; y < h-2; y++) {
  137.       boolean cSwitch = false;
  138.       for (int x = 0; x < w-2; x++) {
  139.         if (n[x][y]) {
  140.           cSwitch = !cSwitch;
  141.         }
  142.         if (cSwitch) {
  143.           if (img.getRGB(x, y) == -1) {
  144.             img.setRGB(x, y, COLOR_BLACK);
  145.           } else {
  146.             img.setRGB(x, y, -1);
  147.           }
  148.         }
  149.       }
  150.     }
  151.   }
  152.  
  153.   Mesh convertPolyToMesh(PolyOutline[] poly) {
  154.     ArrayList<int[]> vertices = new ArrayList<int[]>();
  155.     ArrayList<Integer> triangles = new ArrayList<Integer>();
  156.    
  157.     boolean[][] nodeGridCollective = overlayNodeGrids(poly);
  158.    
  159.     if (poly.length != 2) {
  160.       if (poly[0].nodeMap.size() != poly[1].nodeMap.size()) {
  161.         System.err.println("ERROR: Outlines incompatible");
  162.       }
  163.     }
  164.    
  165.     // top/bottom
  166.     boolean inverted = false;
  167.     boolean ap = !inverted;
  168.     for (int n = 0; n <= 1; n++) {
  169.       int[] v0 = poly[0].nodeMap.get(0);
  170.       int[] v1 = poly[1].nodeMap.get(0);
  171.       int sIndex = vertices.size();
  172.       vertices.add(new int[] {v0[0], v0[1], n});
  173.       vertices.add(new int[] {v1[0], v1[1], n});
  174.       for (int i = 1; i < poly[n].nodeMap.size(); i++) {
  175.         v0 = poly[0].nodeMap.get(i);
  176.         v1 = poly[1].nodeMap.get(i);
  177.        
  178.         vertices.add(new int[] {v0[0], v0[1], n});
  179.         vertices.add(new int[] {v1[0], v1[1], n});
  180.         appendQuad(triangles, vertices.size(), ap);
  181.       }
  182.       if (ap) {
  183.         triangles.add(new Integer(sIndex));             //0 //error?
  184.         triangles.add(new Integer(sIndex+1));           //1 //false
  185.         triangles.add(new Integer(vertices.size()-2));  //2
  186.         triangles.add(new Integer(vertices.size()-2));  //2
  187.         triangles.add(new Integer(sIndex+1));           //1
  188.         triangles.add(new Integer(vertices.size()-1));  //3
  189.       } else {
  190.         triangles.add(new Integer(vertices.size()-2));  //2 //error?
  191.         triangles.add(new Integer(sIndex+1));           //1 //false
  192.         triangles.add(new Integer(sIndex));             //0
  193.         triangles.add(new Integer(vertices.size()-1));  //3
  194.         triangles.add(new Integer(sIndex+1));           //1
  195.         triangles.add(new Integer(vertices.size()-2));  //2
  196.       }
  197.       ap = !ap;
  198.     }
  199.     System.out.println("Surface mesh generated!");
  200.    
  201.     // sides
  202.     ap = inverted;
  203.     for (PolyOutline p: poly) {
  204.       int[] v = p.nodeMap.get(0);
  205.       int sIndex = vertices.size();
  206.       vertices.add(new int[] {v[0], v[1], 0});
  207.       vertices.add(new int[] {v[0], v[1], 1});
  208.       boolean active = true;
  209.       for (int i = 1; i < p.nodeMap.size(); i++) {
  210.         boolean append = true;
  211.         v = p.nodeMap.get(i);
  212.         if (p.crossCheck(v, crossPoints)) {
  213.           active = !active;
  214.           if (active) {
  215.             append = false;
  216.           }
  217.         }
  218.         vertices.add(new int[] {v[0], v[1], 0});
  219.         vertices.add(new int[] {v[0], v[1], 1});
  220.         if (append) {
  221.           appendQuad(triangles, vertices.size(), ap);
  222.         }
  223.       }
  224.       if (ap) {
  225.         triangles.add(new Integer(sIndex));             //0 //error?
  226.         triangles.add(new Integer(sIndex+1));           //1 //false
  227.         triangles.add(new Integer(vertices.size()-2));  //2
  228.         triangles.add(new Integer(vertices.size()-2));  //2
  229.         triangles.add(new Integer(sIndex+1));           //1
  230.         triangles.add(new Integer(vertices.size()-1));  //3
  231.       } else {
  232.         triangles.add(new Integer(vertices.size()-2));  //2 //error?
  233.         triangles.add(new Integer(sIndex+1));           //1 //false
  234.         triangles.add(new Integer(sIndex));             //0
  235.         triangles.add(new Integer(vertices.size()-1));  //3
  236.         triangles.add(new Integer(sIndex+1));           //1
  237.         triangles.add(new Integer(vertices.size()-2));  //2
  238.       }
  239.       ap = !ap;
  240.     }
  241.    
  242.  
  243.    
  244.     // crosshairs
  245.     ap = !inverted;
  246.     for (int n = 0; n <= 1; n++) {
  247.       vertices.add(new int[] {crossPoints[1][0], crossPoints[4][1], n}); //0 //error?
  248.       vertices.add(new int[] {crossPoints[1][0], crossPoints[1][1], n}); //1 //false
  249.       vertices.add(new int[] {crossPoints[0][0], crossPoints[4][1], n}); //2
  250.       vertices.add(new int[] {crossPoints[0][0], crossPoints[0][1], n}); //3
  251.       appendQuad(triangles, vertices.size(), ap);
  252.       vertices.add(new int[] {crossPoints[3][0], crossPoints[3][1], n}); //0 //error?
  253.       vertices.add(new int[] {crossPoints[1][0], crossPoints[5][1], n}); //1 //false
  254.       vertices.add(new int[] {crossPoints[2][0], crossPoints[2][1], n}); //2
  255.       vertices.add(new int[] {crossPoints[0][0], crossPoints[5][1], n}); //3
  256.       appendQuad(triangles, vertices.size(), ap);
  257.       vertices.add(new int[] {crossPoints[0][0], crossPoints[5][1], n}); //0 //error?
  258.       vertices.add(new int[] {crossPoints[0][0], crossPoints[4][1], n}); //1 //false
  259.       vertices.add(new int[] {crossPoints[5][0], crossPoints[5][1], n}); //2
  260.       vertices.add(new int[] {crossPoints[4][0], crossPoints[4][1], n}); //3
  261.       appendQuad(triangles, vertices.size(), ap);
  262.       vertices.add(new int[] {crossPoints[7][0], crossPoints[7][1], n}); //0 //error?
  263.       vertices.add(new int[] {crossPoints[6][0], crossPoints[6][1], n}); //1 //false
  264.       vertices.add(new int[] {crossPoints[1][0], crossPoints[5][1], n}); //2
  265.       vertices.add(new int[] {crossPoints[1][0], crossPoints[4][1], n}); //3
  266.       appendQuad(triangles, vertices.size(), ap);
  267.       vertices.add(new int[] {crossPoints[1][0], crossPoints[5][1], n}); //0 //error?
  268.       vertices.add(new int[] {crossPoints[1][0], crossPoints[4][1], n}); //1 //false
  269.       vertices.add(new int[] {crossPoints[0][0], crossPoints[5][1], n}); //2
  270.       vertices.add(new int[] {crossPoints[0][0], crossPoints[4][1], n}); //3
  271.       appendQuad(triangles, vertices.size(), ap);
  272.       ap = !ap;
  273.     }
  274.     img.setRGB(crossPoints[0][0], crossPoints[4][1], COLOR_BLACK);
  275.     img.setRGB(crossPoints[0][0], crossPoints[5][1], COLOR_BLACK);
  276.     img.setRGB(crossPoints[1][0], crossPoints[6][1], COLOR_BLACK);
  277.     img.setRGB(crossPoints[1][0], crossPoints[7][1], COLOR_BLACK);
  278.    
  279.     //extrude crosshairs
  280.     ap = inverted;
  281.     for (int n = 0; n <= 1; n++) {
  282.       vertices.add(new int[] {crossPoints[0][0], crossPoints[0][1], n}); //error?
  283.       vertices.add(new int[] {crossPoints[0][0], crossPoints[4][1], n}); //false
  284.     }
  285.     appendQuad(triangles, vertices.size(), ap);
  286.     for (int n = 0; n <= 1; n++) {
  287.       vertices.add(new int[] {crossPoints[1][0], crossPoints[6][1], n}); //error?
  288.       vertices.add(new int[] {crossPoints[1][0], crossPoints[1][1], n}); //false
  289.     }
  290.     appendQuad(triangles, vertices.size(), ap);
  291.     for (int n = 0; n <= 1; n++) {
  292.       vertices.add(new int[] {crossPoints[6][0], crossPoints[6][1], n}); //error?
  293.       vertices.add(new int[] {crossPoints[1][0], crossPoints[6][1], n}); //false
  294.     }
  295.     appendQuad(triangles, vertices.size(), ap);
  296.     for (int n = 0; n <= 1; n++) {
  297.       vertices.add(new int[] {crossPoints[1][0], crossPoints[7][1], n}); //error?
  298.       vertices.add(new int[] {crossPoints[7][0], crossPoints[7][1], n}); //false
  299.     }
  300.     appendQuad(triangles, vertices.size(), ap);
  301.     for (int n = 0; n <= 1; n++) {
  302.       vertices.add(new int[] {crossPoints[3][0], crossPoints[3][1], n}); //error?
  303.       vertices.add(new int[] {crossPoints[1][0], crossPoints[7][1], n}); //false
  304.     }
  305.     appendQuad(triangles, vertices.size(), ap);
  306.     for (int n = 0; n <= 1; n++) {
  307.       vertices.add(new int[] {crossPoints[0][0], crossPoints[5][1], n}); //error?
  308.       vertices.add(new int[] {crossPoints[2][0], crossPoints[2][1], n}); //false
  309.     }
  310.     appendQuad(triangles, vertices.size(), ap);
  311.     for (int n = 0; n <= 1; n++) {
  312.       vertices.add(new int[] {crossPoints[5][0], crossPoints[5][1], n}); //error?
  313.       vertices.add(new int[] {crossPoints[0][0], crossPoints[5][1], n}); //false
  314.     }
  315.     appendQuad(triangles, vertices.size(), ap);
  316.     for (int n = 0; n <= 1; n++) {
  317.       vertices.add(new int[] {crossPoints[0][0], crossPoints[4][1], n}); //error?
  318.       vertices.add(new int[] {crossPoints[4][0], crossPoints[4][1], n}); //false
  319.     }
  320.     appendQuad(triangles, vertices.size(), ap);
  321.    
  322.     int[] t = new int[triangles.size()];
  323.     for (int i = 0; i < triangles.size(); i++) {
  324.       t[i] = triangles.get(i).intValue();
  325.     }
  326.     float[][] v = new float[vertices.size()][3];
  327.     for (int i = 0; i < vertices.size(); i++) {
  328.       for (int n = 0; n < 3; n++) {
  329.         v[i][n] = vertices.get(i)[n];
  330.       }
  331.     }
  332.     return new Mesh(v, t);
  333.   }
  334.  
  335.   void flipMesh(Mesh m) {
  336.     for (int i = 0; i < m.getNumVertices(); i++) {
  337.       float vx = m.getVertice(i, 0);
  338.       m.setVertice(i, 0, w - vx - 1);
  339.     }
  340.   }
  341.  
  342.   void appendQuad(ArrayList<Integer> triangles, int start, boolean normalUp) {
  343.     if (normalUp) {
  344.       triangles.add(new Integer(start-2)); //2
  345.       triangles.add(new Integer(start-3)); //1
  346.       triangles.add(new Integer(start-4)); //0
  347.       triangles.add(new Integer(start-1)); //3
  348.       triangles.add(new Integer(start-3)); //1
  349.       triangles.add(new Integer(start-2)); //2
  350.     } else {
  351.       triangles.add(new Integer(start-4)); //0
  352.       triangles.add(new Integer(start-3)); //1
  353.       triangles.add(new Integer(start-2)); //2
  354.       triangles.add(new Integer(start-2)); //2
  355.       triangles.add(new Integer(start-3)); //1
  356.       triangles.add(new Integer(start-1)); //3
  357.     }
  358.   }
  359.  
  360.   boolean[][] overlayNodeGrids(PolyOutline[] poly) {
  361.     boolean[][] finalGrid = new boolean[poly[0].nodeGrid.length][poly[0].nodeGrid[0].length];
  362.     for (PolyOutline p: poly) {
  363.       //System.out.println(p.nodeGrid.length + "*" + p.nodeGrid[0].length);
  364.       for (int y = 0; y < p.nodeGrid[0].length-1; y++) {
  365.         for (int x = 0; x < p.nodeGrid.length-1; x++) {
  366.           if (p.nodeGrid[x][y]) {
  367.             img.setRGB(x, y, COLOR_BLACK);
  368.             finalGrid[x][y] = true;
  369.           }
  370.         }
  371.       }
  372.       img.setRGB(p.nodeMap.get(0)[0], p.nodeMap.get(0)[1], -123456);
  373.     }
  374.     return finalGrid;
  375.   }
  376.  
  377.   public String writeSTL(Mesh m) {
  378.     String result = "solid s\n";
  379.     for (int i = 0; i < m.getNumTriangles(); i+=3) {
  380.       //System.out.println(vertices[triangles[i]] + ":" + vertices[triangles[i]+1] + ":" + vertices[triangles[i]+2]);
  381.       result = result + writeFacet(m.getFacetFromIndex(i));
  382.     }
  383.     result = result + "endsolid s";
  384.     return result;
  385.   }
  386.  
  387.   void scaleMeshVertices(Mesh m, float s, int p, float extrude_height) {
  388.     System.out.println(s + "|" + (p/100f));
  389.     for (int i = 0; i < m.getNumVertices(); i++) {
  390.       for (int n = 0; n < 2; n++) {
  391.         m.setVertice(i, n, (m.getVertice(i, n)/s)*(p/10f));
  392.       }
  393.       m.setVertice(i, 2, m.getVertice(i, 2) * extrude_height);
  394.     }
  395.   }
  396.  
  397.   public String writeFacet(float[][] f) {
  398.     String result = "facet normal 0 0 0\nouter loop\n";
  399.     result = result + "vertex " + f[0][0] + " " + f[0][1] + " " + f[0][2] + "\n";
  400.     result = result + "vertex " + f[1][0] + " " + f[1][1] + " " + f[1][2] + "\n";
  401.     result = result + "vertex " + f[2][0] + " " + f[2][1] + " " + f[2][2] + "\n";
  402.     result = result + "endloop\nendfacet\n";
  403.     return result;
  404.   }
  405.  
  406. }
RAW Paste Data Copied