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.