From 77132d13c4434fa3e320d4516e98c1d8a7df21cc Mon Sep 17 00:00:00 2001 From: adam Date: Sun, 25 Nov 2007 19:43:57 -0800 Subject: [PATCH 1/1] init darcs-hash:20071126034357-5007d-538cebe4569498197ec1e1a53f79348b55540f15.gz --- Makefile | 4 + src/Geom.java | 164 +++++++++ src/StlFile.java | 897 ++++++++++++++++++++++++++++++++++++++++++++++++ src/StlFileParser.java | 99 ++++++ teapot.stl | Bin 0 -> 1300884 bytes 5 files changed, 1164 insertions(+) create mode 100644 Makefile create mode 100644 src/Geom.java create mode 100644 src/StlFile.java create mode 100644 src/StlFileParser.java create mode 100644 teapot.stl diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a9c9949 --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +all: + mkdir -p build + javac -d build `find src -name \*.java` + java -cp build Geom diff --git a/src/Geom.java b/src/Geom.java new file mode 100644 index 0000000..fec07b5 --- /dev/null +++ b/src/Geom.java @@ -0,0 +1,164 @@ +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.media.opengl.*; +import javax.media.opengl.glu.*; + +public class Geom implements GLEventListener { + + public static StlFile stlf = null; + + /** + * Take care of initialization here. + */ + public void init(GLAutoDrawable gld) { + GL gl = gld.getGL(); + GLU glu = new GLU(); + gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl.glViewport(0, 0, 500, 300); + gl.glMatrixMode(GL.GL_PROJECTION); + gl.glLoadIdentity(); + //glu.gluOrtho2D(0.0, 500.0, 0.0, 300.0); + display(gld); + } + + + /** + * Take care of drawing here. + */ + public void display(GLAutoDrawable drawable) { + float red = 0.0f; + float green = 0.0f; + float blue = 0.0f; + GL gl = drawable.getGL(); + gl.glClear(GL.GL_COLOR_BUFFER_BIT); + gl.glPointSize(5.0f); + + for(int i=0; i 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 diff --git a/src/StlFileParser.java b/src/StlFileParser.java new file mode 100644 index 0000000..8743cca --- /dev/null +++ b/src/StlFileParser.java @@ -0,0 +1,99 @@ +import java.io.StreamTokenizer; +import java.io.Reader; +import java.io.IOException; + +/** + * Title: STL Loader + * Description: STL files loader (Supports ASCII and binary files) for Java3D + * Needs JDK 1.4 due to endian problems + * Copyright: Copyright (c) 2001 + * Company: Universidad del Pais Vasco (UPV/EHU) + * @author: Carlos Pedrinaci Godoy + * @version 1.0 + * + * Contact : xenicp@yahoo.es + * + * STL FILE PARSER: + * Extends StreamTokenizer + * For Ascii files + * Each token returned is checked in StlFile.java + * Format of an ASCII STL file: + * + * solid /users/vis/dru/wedge.stl + * facet normal -1 0 0 + * outer loop + * vertex 0.005 1 0 + * vertex 0 0.543 0 + * vertex 0.453 1 1 + * endloop + * endfacet + * . + * . + * . + * endsolid /users/vis/dru/wedge.stl + * + * That Class is necessary because scientific numbers are not correctly readed by Tokenizer + * we must then extend that class and define another getNumber + */ + +public class StlFileParser extends StreamTokenizer +{ + /** + * Constructor: object creation and setup + * + * @param r The Reader instance + */ + public StlFileParser(Reader r) + { + super(r); + setup(); + } + + /** + * Method that sets some params of the Tokenizer for reading the file correctly + */ + public void setup() + { + resetSyntax(); + eolIsSignificant(true); // The End Of Line is important + lowerCaseMode(true); + + // All printable ascii characters + wordChars('!', '~'); + + whitespaceChars(' ', ' '); + whitespaceChars('\n', '\n'); + whitespaceChars('\r', '\r'); + whitespaceChars('\t', '\t'); + }// End setup + + /** + * Gets a number from the stream. Note that we don't recognize + * numbers in the tokenizer automatically because numbers might be in + * scientific notation, which isn't processed correctly by + * StreamTokenizer. The number is returned in nval. + * + * @return boolean. + */ + boolean getNumber() + { + int t; + + try { + nextToken(); + if (ttype != TT_WORD) + throw new IOException("Expected number on line " + lineno()); + nval = (Double.valueOf(sval)).doubleValue(); + } + catch (IOException e) { + System.err.println(e.getMessage()); + return false; + } + catch (NumberFormatException e) { + System.err.println(e.getMessage()); + return false; + } + return true; + } // end of getNumber + +}// End of StlFileParser diff --git a/teapot.stl b/teapot.stl new file mode 100644 index 0000000000000000000000000000000000000000..0c86f6d5acfe19393afb854f019cd92c78c90b63 GIT binary patch literal 1300884 zcmb@PXIK?U(}s@-h@coqB1u71R0JhRnl6%}U<8aPiXtWq2q>Z;Dk9lHP%-BS7yuEN zZnI#(oDfmhoYou=!&iM?ci)-!_qTr-uj{$boawH5s=8;+>@Y8%cK@IMZJwx51pnSg zMwvyhhwpE>T**lm(l>;{`E zIijbL!iguUPw%=$s<`Qk?h9r+2Y#x6v6A<1hDQD0ozE5(8po|SVql< z>kIXTj+Nu!?9q8hbRN2qMC(SfO+!F zks>rQ7zZuSr$Sr16yf~RV7T!-1H%0Dg|t1RVaBp_B)-8G5~MbrJw7*7Mo3kwpXv)y zn!z9>q#$uf<2Z5Yrp`9Udoia)DT2+mK)8D^2i6Cq2!VSC!$jxRaPqpoFurCG9A2G+ zgmtS*V!gf@Gc^=sgj8jkVjzUh3xFn`*+?9ynF^owpQq5#)$Q`TGeVP)8E|N+ExfBa zE$H={0V_)!VB)MIp{2(Zm{-L|ce>+Ln7y}}9_)C-RZ2)zhK-7a_+eAPS<4QI2c@%M zZc#qna^qHo^NliL-0W#EJT@BIT`Lm|mrsT2nF+A#Qh`vvAq?`G#v}2nJOVno?xs=Y zn`MMlW$RNY%$Yt3RQg0BQT{dp#1)(9l^<1N#+5R`E+q^O)no!co;f}g9=fjrkBS1J zvsVao{{U#*V-R}iuCwGv3drV}6RJDF;zOdJ46lm<*fW(U<%Z1yc7lOmPN3LfVE^@Z< zkAc;XtRd~;ROjnHF>r?2fw0&}IJ|Z)=w9K`-nf5?aC*{0(EQQcO-e{rDqV~P#lE?a zq|zOU#RgY|$6MlHxaJXI|LI*NeS+se&lU4A&-<0k?GX(F{1RbFvaYbgFA7?JTf)!L z_PQ{AV;rnLStKK*ss(vEf+8{+5}VIQ!ddsRaAxpy=r!sH5ql*S4`DOGZfCag9AD3c zgY~>M@NJi_&{i)T4t-dSMBuAeg6pp7u;pu!jF75&Ds+YQ-)4Y^6`#QY+D(bp=o&Iz zF%ie-Wr^eLF_7DSE1sjOpxf;46pATo{ zd{jrDqLb!dBd=x#fPPZ4$n&EE=EwWeWRd5`WXz8pzPh3%&PP|}e6)O3NsFs4l7RDa zLaMqkM@Rhcd{i%*$p+3VBC&x5ZX;`%crtVboLy%N*;AP~+GPfeIPU;mYY&NUqi4g@ zLhe^8p)*;4c`+#)v{gn(RXTkRi)XjY26tQTR|gzsGMy{MM9uP%+wEIrBCj76SU-B- zEE9SCXf-PV)_lnqxnDIX{c6$c8LY#IBV_WWS{Wf#y-vy(xnJE<`qlZ0Sxif9C;91p zRlpi0^7`=@>j!$f$m_>TtRKfz3q}>T zvBlBsclQ=#fd2y04L_IHkF8ig`1yGK(7^iPQk^gEMZc<0`qhv7(JZ`cQ_}PMJQ*QX zotTaU`c?H_?pIF?teB~tJ3Br7T6x*BL{SraD!r!;@cL__xMyo9oEhu_u@4Kx#@