?? bbsjava1.txt
字號:
BBS水木清華站∶精華區
發信人: VolVis (arthur), 信區: Java
標 題: Java example(1)
發信站: BBS 水木清華站 (Fri Dec 25 13:36:27 1998) WWW-POST
Dear Everyone:
I just have read a java program to draw a 3d face was written by Daeron
Meyer, The Geometry Center, University of Minnesota. I do think it is a good
program to illustrate the java appletview and the 3d Graphics although it
only draw a polygon without clipping and lingting. It inludes three class:
Viewer3D, Matrix3D and OOGL_OFF. The most important class is OOGL_OFF, I
will
explain it and the other 2 class in the java program.The last part was one
OFF
format file and one html file.I hope it will be helpful to you.
Yours VolVis
Information Department of Peking University
The following will give you a detailed explaination about the class OOGL_OFF
(1) findBB() is to calculate the bounding box of the object
why? the answer is to put all the vertices in a box, so the coordinate
transform can the (0,0,0) to be the object center.
(2) paint() is the most function in the class OOGL_OFF, for it using the
Painter's algorithm to paint the scenes. Do you know the Painter's
algorithm? The algorithm is to align the object in the reverse erder of
their distance from the eye. As common, the eye is placed in minus z
axis,
so the sort the object according to object parameter depth. The the
farther
object will be painted earlier, and the nearest object will be painted
the
latest. Perhaps, the nearer object will hide the farther object. Let's
see
the java program: At first, it will allocate the color for the face
gr[i] = new Color(face[i].cr, face[i].cg, face[i].cb) 0 <= i <= number
of
faces. then quick sort the faces by the qs function whose algorithm is
the same asthe dividing method in data structure. At last paint the
faces by the function g.fillPolygon(vx, vy, face[i].nverts) and paint
the
edges by the function g.drawLine(vx[v], vy[v], vx[v+1], vy[v+1])
(3) the readObject function is to read the faces from the OFF file. The
first
line of OFF file is the tag OFF, the following is number of vertices ,
number of faces, and number of edges. Then the three dimensional data of
vertices is following them. The next thing is data of faces, including
the
number of vertices in the face, the vertex index, and the color of face.
i
In the OFF file, you can add any comment with the head #. Now, if you
are
familiar with the java, you can read the OFF file either. But I have to
remind you that the class StreamTokenizer is a good way to do this work.
/**
*
* Author: Daeron Meyer
* Copyright (c) 1995 by The Geometry Center, University of Minnesota
* Distributed under the terms of the GNU Library General Public License
* 12-14-95
*
*/
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Event;
import java.lang.*;
import java.io.StreamTokenizer;
import java.io.InputStream;
import java.io.IOException;
import java.net.URL;
/**
* class Face: your basic storage class for polygonal face information.
*/
class Face {
public int nverts; // number of vertices
public int index[]; // array of indices
public int cr, cg, cb; // face color in RGB
public int zdepth; // z depth of furthest vertex
Face () {
nverts = 0;
index = null;
cr = 255; cg = 255; cb = 255;
}
Face (int nv) {
nverts = nv;
index = new int[nv];
cr = 255; cg = 255; cb = 255;
}
public void numVerts(int nv) {
nverts = nv;
index = new int[nv];
}
}
/**
* class OOGL_OFF: a class for parsing, storing and rendering OFF 3D models
*
* For more information about OFF files and other OOGL (Object Oriented
* Graphics Library) file formats, check the following URL:
*
* http://www.geom.umn.edu/software/geomview/docs/oogltour.html
*/
public class OOGL_OFF {
Face face[]; // array of faces
boolean transformed, gothead;
Matrix3D mat; // applied 3D transformation
public float xmin, xmax, // bounding box parameters
ymin, ymax,
zmin, zmax;
float vert[]; // array of vertex coordinates
int nverts, nfaces, nedges, // # of vertices, faces, edges
vx[], vy[], // coords for rendering faces
tvert[], // transformed vertices
findex[]; // indices into face list
Color gr[]; // face colors
final int MAX_VERTS = 100; // assume each polygonal face
// has less than 100 vertices.
OOGL_OFF () {
mat = new Matrix3D();
vx = new int[MAX_VERTS];
vy = new int[MAX_VERTS];
nverts = 0;
nedges = 0;
nfaces = 0;
vert = null;
gr = null;
mat.xrot(0); mat.yrot(0);
}
OOGL_OFF (URL loc) { // read object from any URL
this();
try {
readObject(loc.openStream());
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
OOGL_OFF (InputStream is) { // read object from a stream
this();
try {
readObject(is);
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
/* This method parses an OFF file. */
void readObject(InputStream is) throws IOException {
StreamTokenizer stream = new StreamTokenizer (is);
stream.eolIsSignificant(true);
stream.commentChar('#');
gothead = false;
scanhead: // read the header
while (!gothead) {
switch (stream.nextToken()) {
default:
break scanhead;
case StreamTokenizer.TT_EOL:
break;
case StreamTokenizer.TT_WORD:
if ("OFF".equals(stream.sval)) {
System.out.println(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;
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -