/** * Adds a series of polygons by rotating the points list (ps) steps times, and colouring them as * defined by the color array (stripes!). */ public void lathePolygons(float[][] ps, Color[] color, int steps) { float _ps[][] = new float[ps.length][3]; float stepAngle = (float) Math.PI * 2 / steps; // the angle of each step in radians int currColor = 0; float m[][]; for (int step = 0; step < steps; step++) { // translate each point to it next step round m = Tools3d.rotateAboutZ(stepAngle); for (int i = 0; i < ps.length; i++) { Tools3d.applyTo(m, ps[i], _ps[i]); } // build the polygons for (int point = 0; point < ps.length - 1; point++) { this.addPolygon( new float[][] {_ps[point], ps[point], ps[point + 1], _ps[point + 1]}, color[currColor]); } // copy the translated array to the starting array read for the next iteration for (int i = 0; i < ps.length; i++) { ps[i][0] = _ps[i][0]; ps[i][1] = _ps[i][1]; ps[i][2] = _ps[i][2]; } currColor++; if (currColor == color.length) { currColor = 0; } } }
/** * Uses the camera to map all points from model space, (x, y, z) to screen space (x_, y_, z_). * Remember that x_ represents the depth of the point and (y_, z_) maps to the screen (x, y) * co-ords of the point. * * @see CameraMan */ public void transform() { final float[] f = modelViewer.cameraMan.getFocus(); final float[][] m = modelViewer.cameraMan.getMatrix(); final float d = modelViewer.cameraMan.getDistance(); float[] a = new float[3]; visible = false; // set true if any points are visble to the camera for (int i = 0; i < npoints * 3; i += 3) { a[0] = ps[i] - f[0]; a[1] = ps[i + 1] - f[1]; a[2] = ps[i + 2] - f[2]; Tools3d.applyTo(m, a, a); visibles[i / 3] = Tools3d.projectYZ(a, a, d); ps_[i] = a[0]; if (visibles[i / 3]) { modelViewer.cameraMan.scaleToScreen(a); ps_[i + 1] = a[1]; ps_[i + 2] = a[2]; visible = true; } // depth bounding box if (i == 0) { x_min = x_max = ps_[i]; } else { if (ps_[i] < x_min) x_min = ps_[i]; if (ps_[i] > x_max) x_max = ps_[i]; } } }
/** Dumps the data of this 3d shape. */ public String toString() { StringBuffer sb = new StringBuffer(); // number of polygons sb.append(polygons.length + "\n"); // loop - one line per polygon for (int i = 0; i < polygons.length; i++) { Polygon po = polygons[i]; // todo: tidy up shadows - what a mess ! boolean shadow = false; for (int j = 0; j < MAX_SHADOWS; j++) { if (shadowCasters[j] == i) { shadow = true; break; } } sb.append(shadow ? "t " : "f "); sb.append(po.doubleSided ? "t " : "f "); int rgb = po.c.getRGB(); sb.append("\"" + Integer.toHexString(rgb & 0xFFFFFF) + "\" "); // loop - points in this polygon for (int j = 0; j < po.n; j++) { int index = po.points[j]; sb.append( Tools3d.round(ps[index]) + " " + Tools3d.round(ps[index + 1]) + " " + Tools3d.round(ps[index + 2]) + ", "); } // finished this polygon so end line sb.append("\n"); } return new String(sb); }
/** * Creates the unit normal to the polygon by taking the cross product of the first two edges. * Call with 'nsides' set to two if the polygon is visible from both sides. */ void setNormal() { // We need three points to define two edges. if (n < 3) return; if (normal == null) normal = new float[3]; float[] p0 = {ps[points[0]], ps[points[0] + 1], ps[points[0] + 2]}; float[] p1 = {ps[points[1]], ps[points[1] + 1], ps[points[1] + 2]}; float[] p2 = {ps[points[2]], ps[points[2] + 1], ps[points[2] + 2]}; float[] e1 = new float[3]; float[] e2 = new float[3]; Tools3d.subtract(p1, p0, e1); Tools3d.subtract(p2, p1, e2); Tools3d.cross(e1, e2, normal); Tools3d.makeUnit(normal); dirtyNormal = false; }
/** * Decides if this polygon is a 'back face'. A back face is a polygon that is facing away from * the camera and therefore should not be drawn. If this polygon is double sided then it can not * be a back face. In such a case this routine has the side effect of ensuring that the normal * points towards the camera eye rather than away from it. * * @see Obj3d#draw(Graphics) */ boolean isBackFace(final float[] eye) { if (dirtyNormal) { setNormal(); } p[0] = ps[points[0]]; p[1] = ps[points[0] + 1]; p[2] = ps[points[0] + 2]; Tools3d.subtract(p, eye, ray); if (doubleSided) { // flip the normal if necessary so this is NOT a backface if (Tools3d.dot(normal, ray) >= 0) { Tools3d.scaleBy(normal, -1); } return false; } else { return (Tools3d.dot(normal, ray) >= 0); } }