Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import java.awt.image.*;
- import java.awt.Color;
- import java.awt.*;
- import java.io.*;
- import javax.imageio.*;
- import javax.swing.SwingUtilities;
- import javax.swing.filechooser.*;
- import javax.swing.*;
- import java.util.ArrayList;
- /* This class does the heavy lifting for
- * the conversion of a correctly formatted image
- * into an STL file.
- * */
- public class STLConverter {
- public static final int COLOR_BLACK = -16777216;
- public static final int COLOR_WHITE = -1;
- BufferedImage img;
- BufferedImage template;
- int w, h;
- int[] center;
- int[][] crossPoints;
- public STLConverter() { // 01
- } //45 [] 67
- // 23
- public void setCenterInfo(int[] c, int[][] cPoints) {
- center = c;
- crossPoints = cPoints;
- }
- public String convertImage(BufferedImage i, int scale, float pxcm) {
- w = i.getWidth();
- h = i.getHeight();
- img = i;
- PolyOutline[] outlines = generateNodeMap(8, false);
- outlines[0].optimize(outlines[1].optimize(500, crossPoints));
- Mesh mesh = convertPolyToMesh(outlines);
- flipMesh(mesh);
- scaleMeshVertices(mesh, pxcm, scale, 15f);
- return writeSTL(mesh);
- }
- public void setImageTemplate(BufferedImage i) {
- template = i;
- }
- public PolyOutline[] generateNodeMap(int speckSize, boolean single) {
- boolean broken = false;
- ArrayList<PolyOutline> maps = new ArrayList<PolyOutline>();
- for (int y = 1; y < h-1; y++) {
- for (int x = 1; x < w-1; x++) {
- //System.out.println("----====" + x + ":" + y);
- if (img.getRGB(x, y) == COLOR_BLACK) {
- PolyOutline poly = new PolyOutline(w, h);
- int[] startPos = {x, y};
- int[] currentPos = {x, y};
- poly.add(currentPos);
- //System.out.println(currentPos[0] + ":" + currentPos[1]);
- currentPos = trace(x, y, null, poly);
- while (currentPos[0] != startPos[0] || currentPos[1] != startPos[1]) {
- poly.add(currentPos);
- //System.out.println(currentPos[0] + ":" + currentPos[1]);
- currentPos = trace(currentPos[0], currentPos[1], poly.getPrevPos(), poly);
- }
- invertImage(poly.edgeGrid);
- if (poly.nodeMap.size() > speckSize) {
- maps.add(poly);
- }
- if (single) {
- broken = true;
- break;
- }
- }
- }
- if (broken) {
- break;
- }
- }
- return maps.toArray(new PolyOutline[maps.size()]);
- }
- int[] trace(int x, int y, int[] prevPos, PolyOutline p) {
- int t = 0;
- if (img.getRGB(x-1, y-1) == COLOR_BLACK) {
- t += 1;
- }
- if (img.getRGB(x, y-1) == COLOR_BLACK) {
- t += 2;
- }
- if (img.getRGB(x-1, y) == COLOR_BLACK) {
- t += 4;
- }
- if (img.getRGB(x, y) == COLOR_BLACK) {
- t += 8;
- }
- int[][] coords = new int[0][0];
- if (t == 0) {
- System.err.println("Tracing failed: No black pixels in range");
- } else if (t == 1 || t == 14) {
- coords = new int[][] {{-1, 0}, {0, -1}};
- } else if (t == 2 || t == 13) {
- coords = new int[][] {{1, 0}, {0, -1}};
- } else if (t == 4 || t == 11) {
- coords = new int[][] {{-1, 0}, {0, 1}}; //put this in a table and just index it
- } else if (t == 8 || t == 7) { //do it later
- coords = new int[][] {{1, 0}, {0, 1}}; //dont forget >:C
- } else if (t == 3 || t == 12) {
- coords = new int[][] {{-1, 0}, {1, 0}};
- } else if (t == 5 || t == 10) {
- coords = new int[][] {{0, -1}, {0, 1}};
- } else {
- System.err.println("Tracing failed: Unexpected case");
- }
- int choice = 0;
- if (prevPos != null) {
- //System.out.println("Prev=" + prevPos[0] + ":" + prevPos[1]);
- if (prevPos[0] == coords[0][0]+x && prevPos[1] == coords[0][1]+y) {
- choice = 1;
- }
- }
- if (coords[choice][1] == -1) {
- p.addEdge(x, y-1);
- } if (coords[choice][1] == 1) {
- p.addEdge(x, y);
- }
- int[] result = {coords[choice][0] + x, coords[choice][1] + y};
- return result;
- }
- void invertImage(boolean[][] n) {
- for (int y = 0; y < h-2; y++) {
- boolean cSwitch = false;
- for (int x = 0; x < w-2; x++) {
- if (n[x][y]) {
- cSwitch = !cSwitch;
- }
- if (cSwitch) {
- if (img.getRGB(x, y) == -1) {
- img.setRGB(x, y, COLOR_BLACK);
- } else {
- img.setRGB(x, y, -1);
- }
- }
- }
- }
- }
- Mesh convertPolyToMesh(PolyOutline[] poly) {
- ArrayList<int[]> vertices = new ArrayList<int[]>();
- ArrayList<Integer> triangles = new ArrayList<Integer>();
- boolean[][] nodeGridCollective = overlayNodeGrids(poly);
- if (poly.length != 2) {
- if (poly[0].nodeMap.size() != poly[1].nodeMap.size()) {
- System.err.println("ERROR: Outlines incompatible");
- }
- }
- // top/bottom
- boolean inverted = false;
- boolean ap = !inverted;
- for (int n = 0; n <= 1; n++) {
- int[] v0 = poly[0].nodeMap.get(0);
- int[] v1 = poly[1].nodeMap.get(0);
- int sIndex = vertices.size();
- vertices.add(new int[] {v0[0], v0[1], n});
- vertices.add(new int[] {v1[0], v1[1], n});
- for (int i = 1; i < poly[n].nodeMap.size(); i++) {
- v0 = poly[0].nodeMap.get(i);
- v1 = poly[1].nodeMap.get(i);
- vertices.add(new int[] {v0[0], v0[1], n});
- vertices.add(new int[] {v1[0], v1[1], n});
- appendQuad(triangles, vertices.size(), ap);
- }
- if (ap) {
- triangles.add(new Integer(sIndex)); //0 //error?
- triangles.add(new Integer(sIndex+1)); //1 //false
- triangles.add(new Integer(vertices.size()-2)); //2
- triangles.add(new Integer(vertices.size()-2)); //2
- triangles.add(new Integer(sIndex+1)); //1
- triangles.add(new Integer(vertices.size()-1)); //3
- } else {
- triangles.add(new Integer(vertices.size()-2)); //2 //error?
- triangles.add(new Integer(sIndex+1)); //1 //false
- triangles.add(new Integer(sIndex)); //0
- triangles.add(new Integer(vertices.size()-1)); //3
- triangles.add(new Integer(sIndex+1)); //1
- triangles.add(new Integer(vertices.size()-2)); //2
- }
- ap = !ap;
- }
- System.out.println("Surface mesh generated!");
- // sides
- ap = inverted;
- for (PolyOutline p: poly) {
- int[] v = p.nodeMap.get(0);
- int sIndex = vertices.size();
- vertices.add(new int[] {v[0], v[1], 0});
- vertices.add(new int[] {v[0], v[1], 1});
- boolean active = true;
- for (int i = 1; i < p.nodeMap.size(); i++) {
- boolean append = true;
- v = p.nodeMap.get(i);
- if (p.crossCheck(v, crossPoints)) {
- active = !active;
- if (active) {
- append = false;
- }
- }
- vertices.add(new int[] {v[0], v[1], 0});
- vertices.add(new int[] {v[0], v[1], 1});
- if (append) {
- appendQuad(triangles, vertices.size(), ap);
- }
- }
- if (ap) {
- triangles.add(new Integer(sIndex)); //0 //error?
- triangles.add(new Integer(sIndex+1)); //1 //false
- triangles.add(new Integer(vertices.size()-2)); //2
- triangles.add(new Integer(vertices.size()-2)); //2
- triangles.add(new Integer(sIndex+1)); //1
- triangles.add(new Integer(vertices.size()-1)); //3
- } else {
- triangles.add(new Integer(vertices.size()-2)); //2 //error?
- triangles.add(new Integer(sIndex+1)); //1 //false
- triangles.add(new Integer(sIndex)); //0
- triangles.add(new Integer(vertices.size()-1)); //3
- triangles.add(new Integer(sIndex+1)); //1
- triangles.add(new Integer(vertices.size()-2)); //2
- }
- ap = !ap;
- }
- // crosshairs
- ap = !inverted;
- for (int n = 0; n <= 1; n++) {
- vertices.add(new int[] {crossPoints[1][0], crossPoints[4][1], n}); //0 //error?
- vertices.add(new int[] {crossPoints[1][0], crossPoints[1][1], n}); //1 //false
- vertices.add(new int[] {crossPoints[0][0], crossPoints[4][1], n}); //2
- vertices.add(new int[] {crossPoints[0][0], crossPoints[0][1], n}); //3
- appendQuad(triangles, vertices.size(), ap);
- vertices.add(new int[] {crossPoints[3][0], crossPoints[3][1], n}); //0 //error?
- vertices.add(new int[] {crossPoints[1][0], crossPoints[5][1], n}); //1 //false
- vertices.add(new int[] {crossPoints[2][0], crossPoints[2][1], n}); //2
- vertices.add(new int[] {crossPoints[0][0], crossPoints[5][1], n}); //3
- appendQuad(triangles, vertices.size(), ap);
- vertices.add(new int[] {crossPoints[0][0], crossPoints[5][1], n}); //0 //error?
- vertices.add(new int[] {crossPoints[0][0], crossPoints[4][1], n}); //1 //false
- vertices.add(new int[] {crossPoints[5][0], crossPoints[5][1], n}); //2
- vertices.add(new int[] {crossPoints[4][0], crossPoints[4][1], n}); //3
- appendQuad(triangles, vertices.size(), ap);
- vertices.add(new int[] {crossPoints[7][0], crossPoints[7][1], n}); //0 //error?
- vertices.add(new int[] {crossPoints[6][0], crossPoints[6][1], n}); //1 //false
- vertices.add(new int[] {crossPoints[1][0], crossPoints[5][1], n}); //2
- vertices.add(new int[] {crossPoints[1][0], crossPoints[4][1], n}); //3
- appendQuad(triangles, vertices.size(), ap);
- vertices.add(new int[] {crossPoints[1][0], crossPoints[5][1], n}); //0 //error?
- vertices.add(new int[] {crossPoints[1][0], crossPoints[4][1], n}); //1 //false
- vertices.add(new int[] {crossPoints[0][0], crossPoints[5][1], n}); //2
- vertices.add(new int[] {crossPoints[0][0], crossPoints[4][1], n}); //3
- appendQuad(triangles, vertices.size(), ap);
- ap = !ap;
- }
- img.setRGB(crossPoints[0][0], crossPoints[4][1], COLOR_BLACK);
- img.setRGB(crossPoints[0][0], crossPoints[5][1], COLOR_BLACK);
- img.setRGB(crossPoints[1][0], crossPoints[6][1], COLOR_BLACK);
- img.setRGB(crossPoints[1][0], crossPoints[7][1], COLOR_BLACK);
- //extrude crosshairs
- ap = inverted;
- for (int n = 0; n <= 1; n++) {
- vertices.add(new int[] {crossPoints[0][0], crossPoints[0][1], n}); //error?
- vertices.add(new int[] {crossPoints[0][0], crossPoints[4][1], n}); //false
- }
- appendQuad(triangles, vertices.size(), ap);
- for (int n = 0; n <= 1; n++) {
- vertices.add(new int[] {crossPoints[1][0], crossPoints[6][1], n}); //error?
- vertices.add(new int[] {crossPoints[1][0], crossPoints[1][1], n}); //false
- }
- appendQuad(triangles, vertices.size(), ap);
- for (int n = 0; n <= 1; n++) {
- vertices.add(new int[] {crossPoints[6][0], crossPoints[6][1], n}); //error?
- vertices.add(new int[] {crossPoints[1][0], crossPoints[6][1], n}); //false
- }
- appendQuad(triangles, vertices.size(), ap);
- for (int n = 0; n <= 1; n++) {
- vertices.add(new int[] {crossPoints[1][0], crossPoints[7][1], n}); //error?
- vertices.add(new int[] {crossPoints[7][0], crossPoints[7][1], n}); //false
- }
- appendQuad(triangles, vertices.size(), ap);
- for (int n = 0; n <= 1; n++) {
- vertices.add(new int[] {crossPoints[3][0], crossPoints[3][1], n}); //error?
- vertices.add(new int[] {crossPoints[1][0], crossPoints[7][1], n}); //false
- }
- appendQuad(triangles, vertices.size(), ap);
- for (int n = 0; n <= 1; n++) {
- vertices.add(new int[] {crossPoints[0][0], crossPoints[5][1], n}); //error?
- vertices.add(new int[] {crossPoints[2][0], crossPoints[2][1], n}); //false
- }
- appendQuad(triangles, vertices.size(), ap);
- for (int n = 0; n <= 1; n++) {
- vertices.add(new int[] {crossPoints[5][0], crossPoints[5][1], n}); //error?
- vertices.add(new int[] {crossPoints[0][0], crossPoints[5][1], n}); //false
- }
- appendQuad(triangles, vertices.size(), ap);
- for (int n = 0; n <= 1; n++) {
- vertices.add(new int[] {crossPoints[0][0], crossPoints[4][1], n}); //error?
- vertices.add(new int[] {crossPoints[4][0], crossPoints[4][1], n}); //false
- }
- appendQuad(triangles, vertices.size(), ap);
- int[] t = new int[triangles.size()];
- for (int i = 0; i < triangles.size(); i++) {
- t[i] = triangles.get(i).intValue();
- }
- float[][] v = new float[vertices.size()][3];
- for (int i = 0; i < vertices.size(); i++) {
- for (int n = 0; n < 3; n++) {
- v[i][n] = vertices.get(i)[n];
- }
- }
- return new Mesh(v, t);
- }
- void flipMesh(Mesh m) {
- for (int i = 0; i < m.getNumVertices(); i++) {
- float vx = m.getVertice(i, 0);
- m.setVertice(i, 0, w - vx - 1);
- }
- }
- void appendQuad(ArrayList<Integer> triangles, int start, boolean normalUp) {
- if (normalUp) {
- triangles.add(new Integer(start-2)); //2
- triangles.add(new Integer(start-3)); //1
- triangles.add(new Integer(start-4)); //0
- triangles.add(new Integer(start-1)); //3
- triangles.add(new Integer(start-3)); //1
- triangles.add(new Integer(start-2)); //2
- } else {
- triangles.add(new Integer(start-4)); //0
- triangles.add(new Integer(start-3)); //1
- triangles.add(new Integer(start-2)); //2
- triangles.add(new Integer(start-2)); //2
- triangles.add(new Integer(start-3)); //1
- triangles.add(new Integer(start-1)); //3
- }
- }
- boolean[][] overlayNodeGrids(PolyOutline[] poly) {
- boolean[][] finalGrid = new boolean[poly[0].nodeGrid.length][poly[0].nodeGrid[0].length];
- for (PolyOutline p: poly) {
- //System.out.println(p.nodeGrid.length + "*" + p.nodeGrid[0].length);
- for (int y = 0; y < p.nodeGrid[0].length-1; y++) {
- for (int x = 0; x < p.nodeGrid.length-1; x++) {
- if (p.nodeGrid[x][y]) {
- img.setRGB(x, y, COLOR_BLACK);
- finalGrid[x][y] = true;
- }
- }
- }
- img.setRGB(p.nodeMap.get(0)[0], p.nodeMap.get(0)[1], -123456);
- }
- return finalGrid;
- }
- public String writeSTL(Mesh m) {
- String result = "solid s\n";
- for (int i = 0; i < m.getNumTriangles(); i+=3) {
- //System.out.println(vertices[triangles[i]] + ":" + vertices[triangles[i]+1] + ":" + vertices[triangles[i]+2]);
- result = result + writeFacet(m.getFacetFromIndex(i));
- }
- result = result + "endsolid s";
- return result;
- }
- void scaleMeshVertices(Mesh m, float s, int p, float extrude_height) {
- System.out.println(s + "|" + (p/100f));
- for (int i = 0; i < m.getNumVertices(); i++) {
- for (int n = 0; n < 2; n++) {
- m.setVertice(i, n, (m.getVertice(i, n)/s)*(p/10f));
- }
- m.setVertice(i, 2, m.getVertice(i, 2) * extrude_height);
- }
- }
- public String writeFacet(float[][] f) {
- String result = "facet normal 0 0 0\nouter loop\n";
- result = result + "vertex " + f[0][0] + " " + f[0][1] + " " + f[0][2] + "\n";
- result = result + "vertex " + f[1][0] + " " + f[1][1] + " " + f[1][2] + "\n";
- result = result + "vertex " + f[2][0] + " " + f[2][1] + " " + f[2][2] + "\n";
- result = result + "endloop\nendfacet\n";
- return result;
- }
- }
Add Comment
Please, Sign In to add comment