/* Model3D.java Representation of a 3D model as a wire frame of line segments. History: 12 Jun 2008 If an Exception is encountered while the model is being loaded, reset() before throwing or rethrowing the exception. 10 Jun 2008 Extracted from ThreeD.java and JModel3D.java. */ import java.io.*; /** The representation of a 3D model as a wire frame of line segments. */ public abstract class Model3D { /** Report problems with data file formatting. @param s description of the problem */ public class FileFormatException extends Exception { public FileFormatException(String s) { super(s); } } /** Report problems with adding information to the model. @param s description of the problem */ public class ModelException extends Exception { public ModelException(String s) { super(s); } } public Model3D() { } public Model3D(InputStream is) throws IOException, FileFormatException, ModelException { load(is); } /** Reset model to empty state. */ public abstract void reset(); /** Initialize the model geometry from data contained in a stream. If an exception occurs while the model is being loaded, the model is reset() back to empty. The stream must fit the following format specification:
    # comment character
    v x_val y_val z_val
    l p1_val p2_val type

    x_val, y_val and z_val are floating-point values.
    p1_val and p2_val are zero-based indexes into the vertex array.
    type is a non-negative integer.  type % 8 == 1 indicates a strut.
    All the "v" specs must precede the "l" specs.
    
@param is InputStream in the prescribed format. @exception java.io.IOException See exception documentation for reason. @exception FileFormatException See exception documentation for reason. @exception ModelException See exception documentation for reason. */ public synchronized void load(InputStream is) throws IOException, FileFormatException, ModelException { reset(); Reader r = new BufferedReader(new InputStreamReader(is)); StreamTokenizer st = new StreamTokenizer(r); st.eolIsSignificant(true); st.commentChar('#'); try { while (st.nextToken() != StreamTokenizer.TT_EOF) if (st.ttype == StreamTokenizer.TT_WORD) { if ("v".equals(st.sval)) { // v = "vertex" // point double x = 0, y = 0, z = 0; if (st.nextToken() == StreamTokenizer.TT_NUMBER) { x = st.nval; if (st.nextToken() == StreamTokenizer.TT_NUMBER) { y = st.nval; if (st.nextToken() == StreamTokenizer.TT_NUMBER) { z = st.nval; } else fileFormatException(st.toString()); } else fileFormatException(st.toString()); } else fileFormatException(st.toString()); addPoint(x, y, z); } else if ("l".equals(st.sval)) { // l = "line" // lineSegment int p1 = 0, p2 = 0, type = 0; if (st.nextToken() == StreamTokenizer.TT_NUMBER) { p1 = (int)st.nval; if (st.nextToken() == StreamTokenizer.TT_NUMBER) { p2 = (int)st.nval; if (st.nextToken() == StreamTokenizer.TT_NUMBER) { type = (int)st.nval; } else throw new FileFormatException(st.toString()); } else fileFormatException(st.toString()); } else fileFormatException(st.toString()); addLineSegment(p1, p2, type); } } // TT_WORD token } catch (IOException e) { reset(); throw e; } catch (ModelException e) { reset(); throw e; } computeBoundingSphere(); } /** Handle a FileFormatException by emptying the model and then throwing said exception. @param tokenizerString string from tokenizer when bad format encountered @exception FileFormatException See exception documentation for reason. */ private void fileFormatException(String tokenizerString) throws FileFormatException { reset(); throw new FileFormatException(tokenizerString); } /** Add a point to the model's geometry. @param x x coordinate of point @param y y coordinate of point @param z z coordinate of point */ abstract void addPoint(double x, double y, double z) throws ModelException; /** Add a LineSegment with endpoints p1 and p2 to the model's geometry. @param p1 zero-based index of first endpoint @param p2 zero-based index of second endpoint @param type type value for this line segment */ abstract void addLineSegment(int p1, int p2, int type) throws ModelException; /** Compute the bounding sphere for the model in its current state. */ abstract void computeBoundingSphere(); }