--- /dev/null
+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<stlf.coordArray.length; i+=3) {
+ red -= .09f;
+ green -= .12f;
+ blue -= .15f;
+ if (red < 0.15) red = 1.0f;
+ if (green < 0.15) green = 1.0f;
+ if (blue < 0.15) blue = 1.0f;
+ gl.glColor3f(red, green, blue);
+
+ gl.glBegin(GL.GL_TRIANGLES);
+ for(int j=0; j<3; j++)
+ gl.glVertex3f(stlf.coordArray[i+j].x,
+ stlf.coordArray[i+j].y,
+ stlf.coordArray[i+j].z);
+ gl.glEnd();
+ }
+ }
+
+
+ public void reshape(
+ GLAutoDrawable drawable,
+ int x,
+ int y,
+ int width,
+ int height
+ ) {}
+ public void displayChanged(
+ GLAutoDrawable drawable,
+ boolean modeChanged,
+ boolean deviceChanged
+ ) {}
+
+ /** point in 3-space */
+ public static class P {
+ public final float x, y, z;
+ public P(float x, float y, float z) { this.x = x; this.y = y; this.z = z; }
+ public V minus(P p) { return null; }
+ }
+
+ /** vector in 3-space */
+ public static class V {
+ private final float x, y, z;
+ public V(float x, float y, float z) { this.x = x; this.y = y; this.z = z; }
+ public V norm() { return null; /* FIXME */ }
+ public boolean sameDirection(V v) { throw new Error(); }
+ public V cross(V v) { return null; }
+ }
+
+ /** an edge */
+ public static class E {
+ public final P p1, p2;
+ private T t1, t2;
+ public E(P p1, P p2) { this.p1 = p1; this.p2 = p2; }
+ public boolean equals(Object o) {
+ if (o==null || !(o instanceof E)) return false;
+ E e = (E)o;
+ if (this.p1 == e.p1 && this.p2 == e.p2) return true;
+ if (this.p2 == e.p1 && this.p1 == e.p2) return true;
+ return false;
+ }
+ public P shared(E e) { return null; }
+ }
+
+ /** a triangle (face) */
+ public static class T {
+ public final E e1, e2, e3;
+ public T(E e1, E e2, E e3, V normal) {
+ P p1 = e1.shared(e2);
+ P p2 = e2.shared(e3);
+ P p3 = e3.shared(e1);
+ V norm = p2.minus(p1).cross(p3.minus(p1));
+ if (norm.sameDirection(normal)) {
+ this.e1 = e1;
+ this.e2 = e2;
+ this.e3 = e3;
+ } else {
+ this.e1 = e3;
+ this.e2 = e2;
+ this.e3 = e1;
+ }
+ }
+ public V norm() {
+ P p1 = e1.shared(e2);
+ P p2 = e2.shared(e3);
+ P p3 = e3.shared(e1);
+ return p2.minus(p1).cross(p3.minus(p1)).norm();
+ }
+ public T(E e1, E e2, E e3) { this.e1 = e1; this.e2 = e2; this.e3 = e3; }
+ }
+
+ /** matrix */
+ public static class M {
+ }
+
+ public static void main(String[] s) throws Exception {
+ stlf = new StlFile();
+ stlf.load("teapot.stl");
+ /*
+ for(int i=0; i<stlf.coordArray.length; i+=3) {
+ System.out.println("triangle: (" +
+ stlf.coordArray[i+0] + ", " +
+ stlf.coordArray[i+1] + ", " +
+ stlf.coordArray[i+2] + ")");
+ }
+
+ gi.setCoordinates();
+ gi.setNormals(normArray);
+ gi.setStripCounts(stripCounts);
+
+ GeometryInfo gi = ;
+ ga.convertToIndexedTriangles();
+ GeometryArray ga = ;
+ ga.convertToIndexedTriangles();
+ */
+
+ Geom geom = new Geom();
+
+
+ Frame f = new Frame();
+ GLCapabilities glcaps = new GLCapabilities();
+ GLCanvas glcanvas = new GLCanvas();
+ glcanvas.addGLEventListener(geom);
+ f.add(glcanvas, BorderLayout.CENTER);
+ f.show();
+ f.setSize(500, 300);
+ }
+
+}
--- /dev/null
+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<Number_faces;i++)
+ {
+ stripCounts[i]=3;
+ try
+ {
+ readFacetB(dataBuffer,i);
+ // After each facet there are 2 bytes without information
+ // In the last iteration we dont have to skip those bytes..
+ if(i != Number_faces - 1)
+ {
+ dataBuffer.get();
+ dataBuffer.get();
+ }
+ }
+ catch (IOException e)
+ {
+ // Quitar
+ System.out.println("Format Error: iteration number " + i);
+ throw new IncorrectFormatException();
+ }
+ }//End for
+ }// End file reading
+ }// End else
+ }// End of readBinaryFile
+
+ /**
+ * Method that reads ASCII files
+ * Uses StlFileParser for correct reading and format checking
+ * The beggining of that method is common to binary and ASCII files
+ * We try to detect what king of file it is
+ *
+ * TO-DO:
+ * 1.- Find a best way to decide what kind of file it is
+ * 2.- Is that return (first catch) the best thing to do?
+ *
+ * @param parser The file parser. An instance of StlFileParser.
+ */
+ private void readFile(StlFileParser parser)
+ {
+ int t;
+
+ try{
+ parser.nextToken();
+ }
+ catch (IOException e)
+ {
+ System.err.println("IO Error on line " + parser.lineno() + ": " + e.getMessage());
+ System.err.println("File seems to be empty");
+ return; // ????? Throw ?????
+ }
+
+ // Here we try to detect what kind of file it is (see readSolid)
+ readSolid(parser);
+
+ if(getAscii())
+ { // Ascii file
+ try
+ {
+ parser.nextToken();
+ }
+ catch (IOException e)
+ {
+ System.err.println("IO Error on line " + parser.lineno() + ": " + e.getMessage());
+ }
+
+ // Read all the facets of the object
+ while (parser.ttype != StlFileParser.TT_EOF && !parser.sval.equals("endsolid"))
+ {
+ readFacet(parser);
+ try
+ {
+ parser.nextToken();
+ }
+ catch (IOException e)
+ {
+ System.err.println("IO Error on line " + parser.lineno() + ": " + e.getMessage());
+ }
+ }// End while
+
+ // Why are we out of the while?: EOF or endsolid
+ if(parser.ttype == StlFileParser.TT_EOF)
+ System.err.println("Format Error:expecting 'endsolid', line " + parser.lineno());
+ else
+ {
+ if(DEBUG==1)
+ System.out.println("File readed");
+ }
+ }//End of Ascii reading
+
+ else
+ { // Binary file
+ try{
+ readBinaryFile(getFileName());
+ }
+ catch(IOException e)
+ {
+ System.err.println("Format Error: reading the binary file");
+ }
+ }// End of binary file
+ }//End of readFile
+
+ /**
+ * The Stl File is loaded from the .stl file specified by
+ * the filename.
+ * To attach the model to your scene, call getSceneGroup() on
+ * the Scene object passed back, and attach the returned
+ * BranchGroup to your scene graph. For an example, see
+ * $J3D/programs/examples/ObjLoad/ObjLoad.java.
+ *
+ * @param filename The name of the file with the object to load
+ *
+ * @return Scene The scene with the object loaded.
+ *
+ * @throws FileNotFoundException
+ * @throws IncorrectFormatException
+ * @throws ParsingErrorException
+ */
+ public Scene load(String filename) throws FileNotFoundException,
+ IncorrectFormatException,
+ ParsingErrorException
+ {
+ setBasePathFromFilename(filename);
+ setFileName(filename); // For binary files
+
+ Reader reader = new BufferedReader(new FileReader(filename));
+ return load(reader);
+ } // End of load(String)
+
+ /**
+ * The Stl file is loaded off of the web.
+ * To attach the model to your scene, call getSceneGroup() on
+ * the Scene object passed back, and attach the returned
+ * BranchGroup to your scene graph. For an example, see
+ * $J3D/programs/examples/ObjLoad/ObjLoad.java.
+ *
+ * @param url The url to load the onject from
+ *
+ * @return Scene The scene with the object loaded.
+ *
+ * @throws FileNotFoundException
+ * @throws IncorrectFormatException
+ * @throws ParsingErrorException
+ */
+ public Scene load(URL url) throws FileNotFoundException,
+ IncorrectFormatException,
+ ParsingErrorException
+ {
+ BufferedReader reader;
+
+ setBaseUrlFromUrl(url);
+
+ try {
+ reader = new BufferedReader(new InputStreamReader(url.openStream()));
+ }
+ catch (IOException e) {
+ throw new FileNotFoundException();
+ }
+ fromUrl = true;
+ return load(reader);
+ } // End of load(URL)
+
+ /**
+ * The Stl File is loaded from the already opened file.
+ * To attach the model to your scene, call getSceneGroup() on
+ * the Scene object passed back, and attach the returned
+ * BranchGroup to your scene graph. For an example, see
+ * $J3D/programs/examples/ObjLoad/ObjLoad.java.
+ *
+ * @param reader The reader to read the object from
+ *
+ * @return Scene The scene with the object loaded.
+ *
+ * @throws FileNotFoundException
+ * @throws IncorrectFormatException
+ * @throws ParsingErrorException
+ */
+ public Scene load(Reader reader) throws FileNotFoundException,
+ IncorrectFormatException,
+ ParsingErrorException
+ {
+ // That method calls the method that loads the file for real..
+ // Even if the Stl format is not complicated I've decided to use
+ // a parser as in the Obj's loader included in Java3D
+
+ StlFileParser st=new StlFileParser(reader);
+
+ // Initialize data
+ coordList = new ArrayList();
+ normList = new ArrayList();
+ setAscii(true); // Default ascii
+
+ readFile(st);
+ return makeScene();
+ }
+
+ /**
+ * Method that takes the info from an ArrayList of Point3f
+ * and returns a Point3f[].
+ * Needed for ASCII files as we don't know the number of facets until the end
+ *
+ * @param inList The list to transform into Point3f[]
+ *
+ * @return Point3f[] The result.
+ */
+ private Point3f[] objectToPoint3Array(ArrayList inList)
+ {
+ Point3f outList[] = new Point3f[inList.size()];
+
+ for (int i = 0 ; i < inList.size() ; i++) {
+ outList[i] = (Point3f)inList.get(i);
+ }
+ return outList;
+ } // End of objectToPoint3Array
+
+ /**
+ * Method that takes the info from an ArrayList of Vector3f
+ * and returns a Vector3f[].
+ * Needed for ASCII files as we don't know the number of facets until the end
+ *
+ * TO-DO:
+ * 1.- Here we fill stripCounts...
+ * Find a better place to do it?
+ *
+ * @param inList The list to transform into Point3f[]
+ *
+ * @return Vector3f[] The result.
+ */
+ private Vector3f[] objectToVectorArray(ArrayList inList)
+ {
+ Vector3f outList[] = new Vector3f[inList.size()];
+
+ if(DEBUG==1)
+ System.out.println("Number of facets of the object=" + inList.size());
+
+ // To-do
+ stripCounts = new int[inList.size()];
+ for (int i = 0 ; i < inList.size() ; i++) {
+ outList[i] = (Vector3f)inList.get(i);
+ // To-do
+ stripCounts[i]=3;
+ }
+ return outList;
+ } // End of objectToVectorArray
+
+ /**
+ * Method that creates the SceneBase with the stl file info
+ *
+ * @return SceneBase The scene
+ */
+ private SceneBase makeScene()
+ {
+ // Create Scene to pass back
+ SceneBase scene = new SceneBase();
+ BranchGroup group = new BranchGroup();
+ scene.setSceneGroup(group);
+
+ // Store the scene info on a GeometryInfo
+ GeometryInfo gi = new GeometryInfo(GeometryInfo.TRIANGLE_STRIP_ARRAY);
+
+ // Convert ArrayLists to arrays: only needed if file was not binary
+ if(this.Ascii)
+ {
+ coordArray = objectToPoint3Array(coordList);
+ normArray = objectToVectorArray(normList);
+ }
+
+ gi.setCoordinates(coordArray);
+ gi.setNormals(normArray);
+ gi.setStripCounts(stripCounts);
+
+ // Put geometry into Shape3d
+ Shape3D shape = new Shape3D();
+ shape.setGeometry(gi.getGeometryArray());
+
+ group.addChild(shape);
+ scene.addNamedObject(objectName, shape);
+
+ return scene;
+ } // end of makeScene
+
+ /////////////////////// Accessors and Modifiers ///////////////////////////
+
+ public URL getBaseUrl()
+ {
+ return baseUrl;
+ }
+
+ /**
+ * Modifier for baseUrl, if accessing internet.
+ *
+ * @param url The new url
+ */
+ public void setBaseUrl(URL url)
+ {
+ baseUrl = url;
+ }
+
+ private void setBaseUrlFromUrl(URL url)
+ {
+ StringTokenizer stok =
+ new StringTokenizer(url.toString(), "/\\", true);
+ int tocount = stok.countTokens() - 1;
+ StringBuffer sb = new StringBuffer(MAX_PATH_LENGTH);
+ for(int i = 0; i < tocount ; i++) {
+ String a = stok.nextToken();
+ sb.append(a);
+// if((i == 0) && (!a.equals("file:"))) {
+// sb.append(a);
+// sb.append(java.io.File.separator);
+// sb.append(java.io.File.separator);
+// } else {
+// sb.append(a);
+// sb.append( java.io.File.separator );
+// }
+ }
+ try {
+ baseUrl = new URL(sb.toString());
+ }
+ catch (MalformedURLException e) {
+ System.err.println("Error setting base URL: " + e.getMessage());
+ }
+ } // End of setBaseUrlFromUrl
+
+
+ public String getBasePath()
+ {
+ return basePath;
+ }
+
+ /**
+ * Set the path where files associated with this .stl file are
+ * located.
+ * Only needs to be called to set it to a different directory
+ * from that containing the .stl file.
+ *
+ * @param pathName The new Path to the file
+ */
+ public void setBasePath(String pathName)
+ {
+ basePath = pathName;
+ if (basePath == null || basePath == "")
+ basePath = "." + java.io.File.separator;
+ basePath = basePath.replace('/', java.io.File.separatorChar);
+ basePath = basePath.replace('\\', java.io.File.separatorChar);
+ if (!basePath.endsWith(java.io.File.separator))
+ basePath = basePath + java.io.File.separator;
+ } // End of setBasePath
+
+ /*
+ * Takes a file name and sets the base path to the directory
+ * containing that file.
+ */
+ private void setBasePathFromFilename(String fileName)
+ {
+ // Get ready to parse the file name
+ StringTokenizer stok =
+ new StringTokenizer(fileName, java.io.File.separator);
+
+ // Get memory in which to put the path
+ StringBuffer sb = new StringBuffer(MAX_PATH_LENGTH);
+
+ // Check for initial slash
+ if (fileName!= null && fileName.startsWith(java.io.File.separator))
+ sb.append(java.io.File.separator);
+
+ // Copy everything into path except the file name
+ for(int i = stok.countTokens() - 1 ; 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