X-Git-Url: http://git.megacz.com/?p=anneal.git;a=blobdiff_plain;f=src%2Fedu%2Fberkeley%2Fqfat%2FStlFile.java;fp=src%2Fedu%2Fberkeley%2Fqfat%2FStlFile.java;h=b1eaca6af3366df6c864fe90fb5dab47afe9fd6a;hp=0000000000000000000000000000000000000000;hb=e3aa83b5505dcfbc200e29e5b1701664bb218709;hpb=4b43602a6590a8c44a42e6d68cc1c33a4429eb4e diff --git a/src/edu/berkeley/qfat/StlFile.java b/src/edu/berkeley/qfat/StlFile.java new file mode 100644 index 0000000..b1eaca6 --- /dev/null +++ b/src/edu/berkeley/qfat/StlFile.java @@ -0,0 +1,898 @@ +package edu.berkeley.qfat; +import com.sun.j3d.loaders.Loader; +import com.sun.j3d.loaders.Scene; +import com.sun.j3d.loaders.SceneBase; +import com.sun.j3d.loaders.IncorrectFormatException; +import com.sun.j3d.loaders.ParsingErrorException; +import com.sun.j3d.utils.geometry.GeometryInfo; + +import java.net.URL; +import java.net.MalformedURLException; + +import java.io.Reader; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.InputStreamReader; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +import java.util.StringTokenizer; +import java.util.ArrayList; + +import javax.vecmath.Point3f; +import javax.vecmath.Vector3f; + +import javax.media.j3d.BranchGroup; +import javax.media.j3d.Shape3D; + +// New from JDK 1.4 for endian related problems +import java.nio.ByteOrder; +import java.nio.ByteBuffer; + + + +/** + * Title: STL Loader + * Description: STL files loader (Supports ASCII and binary files) for Java3D + * Needs JDK 1.4 due to endian problems + * Company: Universidad del Pais Vasco (UPV/EHU) + * @author: Carlos Pedrinaci Godoy + * @version: 1.0 + * + * Contact : xenicp@yahoo.es + * + * + * Things TO-DO: + * 1.-We can't read binary files over the net. + * 2.-For binary files if size is lower than expected (calculated with the number of faces) + * the program will block. + * 3.-Improve the way for detecting the kind of stl file? + * Can give us problems if the comment of the binary file begins by "solid" + */ + +public class StlFile implements Loader +{ + private static final int DEBUG = 0; // Sets mode to Debug: outputs every action done + + // Maximum length (in chars) of basePath + private static final int MAX_PATH_LENGTH = 1024; + + // Global variables + private int flag; // Needed cause implements Loader + + private URL baseUrl = null; // Reading files over Internet + private String basePath = null; // For local files + + private boolean fromUrl = false; // Usefull for binary files + private boolean Ascii = true; // File type Ascii -> true o binary -> false + private String fileName = null; + + // Arrays with coordinates and normals + // Needed for reading ASCII files because its size is unknown until the end + private ArrayList coordList; // Holds Point3f + private ArrayList normList; // Holds Vector3f + + // GeometryInfo needs Arrays + public Point3f[] coordArray = null; + public Vector3f[] normArray = null; + + // Needed because TRIANGLE_STRIP_ARRAY + // As the number of strips = the number of faces it's filled in objectToVectorArray + public int[] stripCounts = null; + + // Default = Not available + private String objectName=new String("Not available"); + + /** + * Constructor + */ + public StlFile() + { + } + + /** + * Method that reads the EOL + * Needed for verifying that the file has a correct format + * + * @param parser The file parser. An instance of StlFileParser. + */ + private void readEOL(StlFileParser parser) + { + try{ + parser.nextToken(); + } + catch (IOException e) + { + System.err.println("IO Error on line " + parser.lineno() + ": " + e.getMessage()); + } + if(parser.ttype != StlFileParser.TT_EOL) + { + System.err.println("Format Error:expecting End Of Line on line " + parser.lineno()); + } + } + + /** + * Method that reads the word "solid" and stores the object name. + * It also detects what kind of file it is + * TO-DO: + * 1.- Better way control of exceptions? + * 2.- Better way to decide between Ascii and Binary? + * + * @param parser The file parser. An instance of StlFileParser. + */ + private void readSolid(StlFileParser parser) + { + if( !parser.sval.equals("solid")) + { + //System.out.println("Expecting solid on line " + parser.lineno()); + // If the first word is not "solid" then we consider the file is binary + // Can give us problems if the comment of the binary file begins by "solid" + this.setAscii(false); + } + else // It's an ASCII file + { + try{ + parser.nextToken(); + } + catch (IOException e) + { + System.err.println("IO Error on line " + parser.lineno() + ": " + e.getMessage()); + } + if( parser.ttype != StlFileParser.TT_WORD) + { + // Is the object name always provided??? + System.err.println("Format Error:expecting the object name on line " + parser.lineno()); + } + else + { // Store the object Name + this.setObjectName(new String(parser.sval)); + if(DEBUG==1) + { + System.out.println("Object Name:" + this.getObjectName().toString()); + } + this.readEOL(parser); + } + } + }//End of readSolid + + /** + * Method that reads a normal + * + * @param parser The file parser. An instance of StlFileParser. + */ + private void readNormal(StlFileParser parser) + { + Vector3f v = new Vector3f(); + + if(!(parser.ttype==StlFileParser.TT_WORD && parser.sval.equals("normal"))) + { + System.err.println("Format Error:expecting 'normal' on line " + parser.lineno()); + } + else + { + if (parser.getNumber()) + { + v.x=(float)parser.nval; + + if(DEBUG==1) + { + System.out.println("Normal:"); + System.out.print("X=" + v.x + " "); + } + + if (parser.getNumber()) + { + v.y=(float)parser.nval; + if(DEBUG==1) + System.out.print("Y=" + v.y + " "); + + if (parser.getNumber()) + { + v.z=(float)parser.nval; + if(DEBUG==1) + System.out.println("Z=" + v.z); + + // We add that vector to the Normal's array + this.normList.add(v); + this.readEOL(parser); + } + else System.err.println("Format Error:expecting coordinate on line " + parser.lineno()); + } + else System.err.println("Format Error:expecting coordinate on line " + parser.lineno()); + } + else System.err.println("Format Error:expecting coordinate on line " + parser.lineno()); + } + }// End of Read Normal + + /** + * Method that reads the coordinates of a vector + * + * @param parser The file parser. An instance of StlFileParser. + */ + private void readVertex(StlFileParser parser) + { + Point3f p = new Point3f(); + + if(!(parser.ttype==StlFileParser.TT_WORD && parser.sval.equals("vertex"))) + { + System.err.println("Format Error:expecting 'vertex' on line " + parser.lineno()); + } + else + { + if (parser.getNumber()) + { + p.x=(float)parser.nval; + + if(DEBUG==1) + { + System.out.println("Vertex:"); + System.out.print("X=" + p.x + " "); + } + + if (parser.getNumber()) + { + p.y=(float)parser.nval; + if(DEBUG==1) + System.out.print("Y=" + p.y + " "); + + if (parser.getNumber()) + { + p.z=(float)parser.nval; + if(DEBUG==1) + System.out.println("Z=" + p.z); + + // We add that vertex to the array of vertex + coordList.add(p); + readEOL(parser); + } + else System.err.println("Format Error: expecting coordinate on line " + parser.lineno()); + } + else System.err.println("Format Error: expecting coordinate on line " + parser.lineno()); + } + else System.err.println("Format Error: expecting coordinate on line " + parser.lineno()); + } + }//End of read vertex + + /** + * Method that reads "outer loop" and then EOL + * + * @param parser The file parser. An instance of StlFileParser. + */ + private void readLoop(StlFileParser parser) + { + if(!(parser.ttype==StlFileParser.TT_WORD && parser.sval.equals("outer"))) + { + System.err.println("Format Error:expecting 'outer' on line " + parser.lineno()); + } + else + { + try{ + parser.nextToken(); + } + catch (IOException e) + { + System.err.println("IO error on line " + parser.lineno() + ": " + e.getMessage()); + } + if(!(parser.ttype==StlFileParser.TT_WORD && parser.sval.equals("loop"))) + { + System.err.println("Format Error:expecting 'loop' on line " + parser.lineno()); + } + else readEOL(parser); + } + }//End of readLoop + + /** + * Method that reads "endloop" then EOL + * + * @param parser The file parser. An instance of StlFileParser. + */ + private void readEndLoop(StlFileParser parser) + { + if(!(parser.ttype==StlFileParser.TT_WORD && parser.sval.equals("endloop"))) + { + System.err.println("Format Error:expecting 'endloop' on line " + parser.lineno()); + } + else readEOL(parser); + }//End of readEndLoop + + /** + * Method that reads "endfacet" then EOL + * + * @param parser The file parser. An instance of StlFileParser. + */ + private void readEndFacet(StlFileParser parser) + { + if(!(parser.ttype==StlFileParser.TT_WORD && parser.sval.equals("endfacet"))) + { + System.err.println("Format Error:expecting 'endfacet' on line " + parser.lineno()); + } + else readEOL(parser); + }//End of readEndFacet + + /** + * Method that reads a face of the object + * (Cares about the format) + * + * @param parser The file parser. An instance of StlFileParser. + */ + private void readFacet(StlFileParser parser) + { + if(!(parser.ttype==StlFileParser.TT_WORD && parser.sval.equals("facet"))) + { + System.err.println("Format Error:expecting 'facet' on line " + parser.lineno()); + } + else + { + try{ + parser.nextToken(); + readNormal(parser); + + parser.nextToken(); + readLoop(parser); + + parser.nextToken(); + readVertex(parser); + + parser.nextToken(); + readVertex(parser); + + parser.nextToken(); + readVertex(parser); + + parser.nextToken(); + readEndLoop(parser); + + parser.nextToken(); + readEndFacet(parser); + } + catch (IOException e) + { + System.err.println("IO Error on line " + parser.lineno() + ": " + e.getMessage()); + } + } + }// End of readFacet + + /** + * Method that reads a face in binary files + * All binary versions of the methods end by 'B' + * As in binary files we can read the number of faces, we don't need + * to use coordArray and normArray (reading binary files should be faster) + * + * @param in The ByteBuffer with the data of the object. + * @param index The facet index + * + * @throws IOException + */ + private void readFacetB(ByteBuffer in, int index) throws IOException + { + //File structure: Normal Vertex1 Vertex2 Vertex3 + Vector3f normal = new Vector3f(); + Point3f vertex = new Point3f(); + + if(DEBUG==1) + System.out.println("Reading face number " + index); + + // Read the Normal + normArray[index]=new Vector3f(); + normArray[index].x=in.getFloat(); + normArray[index].y=in.getFloat(); + normArray[index].z=in.getFloat(); + + if(DEBUG==1) + System.out.println("Normal: X=" + normArray[index].x + " Y=" + normArray[index].y + " Z=" + normArray[index].z); + + // Read vertex1 + coordArray[index*3] = new Point3f(); + coordArray[index*3].x=in.getFloat(); + coordArray[index*3].y=in.getFloat(); + coordArray[index*3].z=in.getFloat(); + + if(DEBUG==1) + System.out.println("Vertex 1: X=" + coordArray[index*3].x + " Y=" + coordArray[index*3].y + " Z=" + coordArray[index*3].z); + + // Read vertex2 + coordArray[index*3+1] = new Point3f(); + coordArray[index*3+1].x=in.getFloat(); + coordArray[index*3+1].y=in.getFloat(); + coordArray[index*3+1].z=in.getFloat(); + + if(DEBUG==1) + System.out.println("Vertex 2: X=" + coordArray[index*3+1].x + " Y=" + coordArray[index*3+1].y + " Z=" + coordArray[index*3+1].z); + + // Read vertex3 + coordArray[index*3+2] = new Point3f(); + coordArray[index*3+2].x=in.getFloat(); + coordArray[index*3+2].y=in.getFloat(); + coordArray[index*3+2].z=in.getFloat(); + + if(DEBUG==1) + System.out.println("Vertex 3: X=" + coordArray[index*3+2].x + " Y=" + coordArray[index*3+2].y + " Z=" + coordArray[index*3+2].z); + + }// End of readFacetB + + /** + * Method for reading binary files + * Execution is completly different + * It uses ByteBuffer for reading data and ByteOrder for retrieving the machine's endian + * (Needs JDK 1.4) + * + * TO-DO: + * 1.-Be able to read files over Internet + * 2.-If the amount of data expected is bigger than what is on the file then + * the program will block forever + * + * @param file The name of the file + * + * @throws IOException + */ + private void readBinaryFile(String file) throws IOException + { + FileInputStream data; // For reading the file + ByteBuffer dataBuffer; // For reading in the correct endian + byte[] Info=new byte[80]; // Header data + byte[] Array_number= new byte[4]; // Holds the number of faces + byte[] Temp_Info; // Intermediate array + + int Number_faces; // First info (after the header) on the file + + if(DEBUG==1) + System.out.println("Machine's endian: " + ByteOrder.nativeOrder()); + + // Get file's name + if(fromUrl) + { + // FileInputStream can only read local files!? + System.out.println("This version doesn't support reading binary files from internet"); + } + else + { // It's a local file + data = new FileInputStream(file); + + // First 80 bytes aren't important + if(80 != data.read(Info)) + { // File is incorrect + //System.out.println("Format Error: 80 bytes expected"); + throw new IncorrectFormatException(); + } + else + { // We must first read the number of faces -> 4 bytes int + // It depends on the endian so.. + + data.read(Array_number); // We get the 4 bytes + dataBuffer = ByteBuffer.wrap(Array_number); // ByteBuffer for reading correctly the int + dataBuffer.order(ByteOrder.nativeOrder()); // Set the right order + Number_faces = dataBuffer.getInt(); + + Temp_Info = new byte[50*Number_faces]; // Each face has 50 bytes of data + + data.read(Temp_Info); // We get the rest of the file + + dataBuffer = ByteBuffer.wrap(Temp_Info); // Now we have all the data in this ByteBuffer + dataBuffer.order(ByteOrder.nativeOrder()); + + if(DEBUG==1) + System.out.println("Number of faces= " + Number_faces); + + // We can create that array directly as we know how big it's going to be + coordArray = new Point3f[Number_faces*3]; // Each face has 3 vertex + normArray = new Vector3f[Number_faces]; + stripCounts = new int[Number_faces]; + + for(int i=0;i 0 ; i--) { + String a = stok.nextToken(); + sb.append(a); + sb.append(java.io.File.separator); + } + setBasePath(sb.toString()); + } // End of setBasePathFromFilename + + public int getFlags() + { + return flag; + } + + public void setFlags(int parm) + { + this.flag=parm; + } + + public boolean getAscii() + { + return this.Ascii; + } + + public void setAscii(boolean tipo) + { + this.Ascii = tipo; + } + + + public String getFileName() + { + return this.fileName; + } + + public void setFileName(String filename) + { + this.fileName=new String(filename); + } + + + public String getObjectName() + { + return this.objectName; + } + + public void setObjectName(String name) + { + this.objectName = name; + } + +} // End of package stl_loader \ No newline at end of file