public class Vect { Vect (URL loc) { // read object from any URL this(); try { readVect(loc.openStream()); } catch (IOException e) { System.out.println(e.getMessage()); } } Vect (InputStream is) { // read object from a stream this(); try { readVect(is); } catch (IOException e) { System.out.println(e.getMessage()); } } void readVect(InputStream is) throws IOException { StreamTokenizer stream = new StreamTokenizer (is); scanvect: // read the header while (stream.nextToken() != StreamTokenizer.TT_WORD || !"VECT".equals(stream.sval)) ; switch (stream.nextToken()) { default: break scanhead; case StreamTokenizer.TT_EOL: break; case StreamTokenizer.TT_WORD: if ("OFF".equals(stream.sval)) { nverts = 0; nfaces = 0; nedges = 0; while (stream.nextToken() == StreamTokenizer.TT_EOL) {}; if (stream.ttype == StreamTokenizer.TT_NUMBER) { nverts = (int)stream.nval; if (stream.nextToken() == StreamTokenizer.TT_NUMBER) { nfaces = (int)stream.nval; if (stream.nextToken() == StreamTokenizer.TT_NUMBER) { nedges = (int)stream.nval; gothead = true; } else throw new IOException("Can't read OFF file"); } else throw new IOException("Can't read OFF file"); } else throw new IOException("Can't read OFF file"); } break; case StreamTokenizer.TT_NUMBER: break; } } vert = new float[nverts * 3]; face = new Face[nfaces]; findex = new int[nfaces]; for (int i = 0; i < nfaces; i++) { findex[i] = i; } int num = 0; int coordnum = 0; scanverts: // read the vertices while (num < nverts) { switch (stream.nextToken()) { default: break; case StreamTokenizer.TT_EOL: if (coordnum > 2) { coordnum = 0; num++; } break; case StreamTokenizer.TT_NUMBER: if (coordnum < 3) { vert[num*3 + coordnum] = (float)stream.nval; coordnum++; } } } num = 0; coordnum = 0; boolean gotnum = false; scanfaces: // read the faces while (num < nfaces) { switch (stream.nextToken()) { default: break; case StreamTokenizer.TT_EOL: if (gotnum) { num++; } gotnum = false; break; case StreamTokenizer.TT_NUMBER: if (!gotnum) { face[num] = new Face(); face[num].numVerts((int)stream.nval); gotnum = true; coordnum = 0; } else if (coordnum < face[num].nverts) { face[num].index[coordnum] = 3 * (int)stream.nval; coordnum++; } else { face[num].cr = 255; face[num].cg = 255; face[num].cb = 255; float val = (float)stream.nval; if (val <= 1) { val *= 255; } face[num].cr = (int)val; if (stream.nextToken() != StreamTokenizer.TT_EOL) { val = (float)stream.nval; if (val <= 1) { val *= 255; } face[num].cg = (int)val; if (stream.nextToken() != StreamTokenizer.TT_EOL) { val = (float)stream.nval; if (val <= 1) { val *= 255; } face[num].cb = (int)val; } else { face[num].cr = 255; face[num].cg = 255; face[num].cb = 255; num++; gotnum = false; } } else { face[num].cr = 255; face[num].cg = 255; face[num].cb = 255; num++; gotnum = false; } } break; } } } /* transform all points in model */ void transform() { if (transformed || nverts <= 0) return; if (tvert == null) tvert = new int[nverts*3]; mat.transform(vert, tvert, nverts); transformed = true; } /** * The quick sort algorithm in this method is used for sorting faces * from back to front by z depth values. */ void qs(int left, int right) { int i, j, x, y; i = left; j = right; x = face[findex[(left+right)/2]].zdepth; do { while (face[findex[i]].zdepth > x && i < right) i++; while (x > face[findex[j]].zdepth && j > left) j--; if (i <= j) { y = findex[i]; findex[i] = findex[j]; findex[j] = y; i++; j--; } } while (i <= j); if (left < j) qs(left, j); if (i < right) qs(i, right); } /* Paint myself to the graphics context. */ void paint(Graphics g) { if (vert == null || nverts <= 0) return; transform(); if (gr == null) { // allocate colors if // they haven't been gr = new Color[nfaces]; // allocated already for (int i = 0; i < nfaces; i++) { gr[i] = new Color(face[i].cr, face[i].cg, face[i].cb); } } /** * Calculate the average z depth of faces and use this to sort them. * This is called the "Painter's algorithm" and although it works in * some case, does *not* always provide a correct ordering. Sometimes * a correct ordering is impossible, especially in the case of mutually * overlapping polygons. */ for (int i = 0; i < nfaces; i++) { face[i].zdepth = 0; for (int c = 0; c < face[i].nverts; c++) { if (face[i].zdepth < tvert[face[i].index[c]+2]) face[i].zdepth = tvert[face[i].index[c]+2]; } } qs(0, nfaces-1); // quick sort the faces for (int f = 0; f < nfaces; f++) { int i = findex[f]; int v = 0; for (int c = 0; c < face[i].nverts; c++) { vx[c] = tvert[face[i].index[c]]; vy[c] = tvert[face[i].index[c]+1]; } g.setColor(gr[i]); g.fillPolygon(vx, vy, face[i].nverts); // draw each face g.setColor(Color.black); for (v = 0; v < (face[i].nverts-1); v++) { g.drawLine(vx[v], vy[v], vx[v+1], vy[v+1]); // draw the face edges } g.drawLine(vx[v], vy[v], vx[0], vy[0]); } } /* calculate the bounding box of our object: */ void findBB() { if (nverts <= 0) return; float v[] = vert; float xmin = v[0], xmax = xmin; float ymin = v[1], ymax = ymin; float zmin = v[2], zmax = zmin; for (int i = nverts * 3; (i -= 3) > 0;) { float x = v[i]; if (x < xmin) xmin = x; if (x > xmax) xmax = x; float y = v[i + 1]; if (y < ymin) ymin = y; if (y > ymax) ymax = y; float z = v[i + 2]; if (z < zmin) zmin = z; if (z > zmax) zmax = z; } this.xmax = xmax; this.xmin = xmin; this.ymax = ymax; this.ymin = ymin; this.zmax = zmax; this.zmin = zmin; } }