/* 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();
}