I had to process some CAD files for my rapid prototyping machine project so I came up with the following as a starting point. An STL files describe a set of triangular facets that form a mesh that approximates any three dimensional shape. I wrote this code to allow me to read a file and generate an array of facet data from the binary STL format.
We need a few helper classes.
An ordered triplet of 32 bit floats.
public class Triplet{ public float x,y,z; public Triplet(float x, float y, float z){ this.x = x; this.y = y; this.z = z; } public String toString(){ return "x:" + x + " y:" + y + " z:" + z; } public boolean equals(Triplet other){ if(this.x != other.x) return false; if(this.y != other.y) return false; if(this.z != other.z) return false; return true; } }
A Vector class sub-classed from Triplet.
public class Vector extends Triplet{ public Vector(float x, float y, float z){ super(x,y,z); } public String toString(){ return "Vector " + super.toString(); } }
A Vertex class sub-classed from Triplet.
public class Vertex extends Triplet{ public Vertex(float x, float y, float z){ super(x,y,z); } public String toString(){ return "Vertex " + super.toString(); } }
A Facet class to represent the triangles in the STL mesh.
public class Facet { /* While the ASCII STL specification allows for n-sided facets * where n > 2, the binary specification only allows triangular * facets. This class will also only represent triangular * facets. */ Vector normalVector; Vertex v1, v2, v3; Edge edge1, edge2, edge3; public Facet(Vector normalVector, Vertex v1, Vertex v2, Vertex v3){ /* TODO make sure all vertices are used in the correct order as * described in the file. Order matters! Same with edges. */ this.normalVector = normalVector; this.v1 = v1; this.v2 = v2; this.v3 = v3; edge1 = new Edge(v1,v2); edge2 = new Edge(v2,v3); edge3 = new Edge(v3,v1); } public String toString(){ StringBuilder s = new StringBuilder(); s.append("normal"); s.append(normalVector.toString()); s.append("\n"); s.append(v1.toString()); s.append("\n"); s.append(v2.toString()); s.append("\n"); s.append(v3.toString()); return s.toString(); } }
And here is the class that does all the work: the STL_Reader class.
import java.io.File; import java.io.FileInputStream; import java.io.DataInputStream; import java.io.IOException;
The pre tag breaks on this block of code; so here it is without indentation.
private String fileName;
private File file;
private FileInputStream fileStream;
private DataInputStream dataStream;
private int facetCount;
private Facet[] facets;
private byte[] header; //this needs to become an object
/**
* Try to open and represent a binary STL file.
*/
public STL_Reader(String fileName) throws STL_ReaderException {
this.fileName = fileName;
header = new byte[80];
//TODO: boolean flag doesn't really say what went went wrong
boolean itWorked = parse();
if(!itWorked)
throw new STL_ReaderException();
}
/**
* Get all of the triangular facets contained in the file.
*/
public Facet[] getFacets(){
return facets;
}
private boolean parse(){
try{
file = new File(fileName);
fileStream = new FileInputStream(file);
dataStream = new DataInputStream(fileStream);
/*read the 80 byte header*/
for(int i=0;i
header[i] = dataStream.readByte();
/*next is a 4 byte unsigned int with the number of facets*/
byte[] facetCountBytes = new byte[4];
dataStream.read(facetCountBytes);
facetCount = Conversions.packInteger(facetCountBytes);
/*make facets hold of size facetCount*/
facets = new Facet[facetCount];
/*read in each facet*/
for(int i = 0;i
float x,y,z;
byte[] byteBuffer = new byte[4];
/* TODO: all of these vector reads need to be rolled
* into an inner loop.
*/
//normal vector
dataStream.read(byteBuffer);
x = Conversions.packFloat(byteBuffer);
dataStream.read(byteBuffer);
y = Conversions.packFloat(byteBuffer);
dataStream.read(byteBuffer);
z = Conversions.packFloat(byteBuffer);
Vector normal = new Vector(x,y,z);
//vertex 1
dataStream.read(byteBuffer);
x = Conversions.packFloat(byteBuffer);
dataStream.read(byteBuffer);
y = Conversions.packFloat(byteBuffer);
dataStream.read(byteBuffer);
z = Conversions.packFloat(byteBuffer);
Vertex v1 = new Vertex(x,y,z);
//vertex 2
dataStream.read(byteBuffer);
x = Conversions.packFloat(byteBuffer);
dataStream.read(byteBuffer);
y = Conversions.packFloat(byteBuffer);
dataStream.read(byteBuffer);
z = Conversions.packFloat(byteBuffer);
Vertex v2 = new Vertex(x,y,z);
//vertex 3
dataStream.read(byteBuffer);
x = Conversions.packFloat(byteBuffer);
dataStream.read(byteBuffer);
y = Conversions.packFloat(byteBuffer);
dataStream.read(byteBuffer);
z = Conversions.packFloat(byteBuffer);
Vertex v3 = new Vertex(x,y,z);
facets[i] = new Facet(normal, v1, v2, v3);
//System.out.println(facets[i].toString());
//need to throw out two padding bytes
dataStream.read();
dataStream.read();
}
}catch(IOException e){
e.printStackTrace();
return false;
}
return true;
}
}
So using this class I can now do something like:
Facet[] faces = (new STL_Reader(filename)).getFacets(); for(Facet facet : faces) System.out.println(facet);
To see all the facets contained in the file.