?? threed.java
字號:
/* A set of classes to parse, represent and display 3D wireframe models represented in Wavefront .obj format. *//* I adapted this program, so that it doesn't read in a file any more, but gets the vertices and connections directly by an instance of the 'RoboProto' class. The orignal program is from the book 'Hooked on Java'.*/package RoboPackII;import java.applet.Applet;import java.awt.Graphics;import java.awt.Color;import java.awt.Event;import java.awt.Image;import java.awt.*;class FileFormatException extends Exception { public FileFormatException(String s) { super(s); }}/** The representation of a 3D model */class Model3D { float[] vert; int tvert[]; int nvert = 0, maxvert; int[] con; int ncon = 0, maxcon; boolean transformed; Matrix3D mat; RoboProto rob; Image offscreen; // to double-buffer the image float xmin, xmax, ymin, ymax, zmin, zmax; Model3D (RoboProto datarob) { mat = new Matrix3D (); rob = datarob; offscreen = rob.roboCanvas.createImage(rob.canvasSize, rob.canvasSize); maxvert = rob.numberOfPoints + 4;// 4 vert. for the coodinates system maxcon = rob.numberOfEdges + 3; // 3 connections for the --"--"-- vert = new float[maxvert * 3]; con = new int[maxcon]; for (int i = 0; i < rob.numberOfPoints; i++) addVert((float) rob.PL[i].x, (float) rob.PL[i].y, (float) rob.PL[i].z); addVert(-15.0f, 0.0f, 0.0f);// my coordinates system origin addVert(-12.0f, 0.0f, 0.0f);//point on the x-axis addVert(-15.0f, 3.0f, 0.0f);//point on the y-axis addVert(-15.0f, 0.0f, 3.0f);//point on the z-axis for (int i = 0; i < rob.numberOfEdges; i++) add((int) rob.el[i].p1, (int) rob.el[i].p2); add(rob.numberOfPoints, rob.numberOfPoints + 1);//connects the origin // and the point on the x-axis add(rob.numberOfPoints, rob.numberOfPoints + 2);//connects the origin // and the point on the y-axis add(rob.numberOfPoints, rob.numberOfPoints + 3);//connects the origin // and the point on the z-axis } /** Add a vertex to this model */ int addVert(float x, float y, float z) { int i = nvert; if (i >= maxvert) if (vert == null) { maxvert = 100; vert = new float[maxvert * 3]; } else { maxvert *= 2; float nv[] = new float[maxvert * 3]; System.arraycopy(vert, 0, nv, 0, vert.length); vert = nv; } i *= 3; vert[i] = x; vert[i + 1] = y; vert[i + 2] = z; return nvert++; } /** Add a line from vertex p1 to vertex p2 */ void add(int p1, int p2) { int i = ncon; if (p1 >= nvert || p2 >= nvert) return; if (i >= maxcon) if (con == null) { maxcon = 100; con = new int[maxcon]; } else { maxcon *= 2; int nv[] = new int[maxcon]; System.arraycopy(con, 0, nv, 0, con.length); con = nv; } if (p1 > p2) { int t = p1; p1 = p2; p2 = t; } con[i] = (p1 << 16) | p2; ncon = i + 1; } /** Transform all the points in this model */ void transform() { if (transformed || nvert <= 0) return; if (tvert == null || tvert.length < nvert * 3) tvert = new int[nvert*3]; mat.transform(vert, tvert, nvert); transformed = true; } private void sort(int lo0, int hi0) { int a[] = con; int lo = lo0; int hi = hi0; if (lo >= hi) return; int mid = a[(lo + hi) / 2]; while (lo < hi) { while (lo < hi && a[lo] < mid) { lo++; } while (lo < hi && a[hi] >= mid) { hi--; } if (lo < hi) { int T = a[lo]; a[lo] = a[hi]; a[hi] = T; } } if (hi < lo) { int T = hi; hi = lo; lo = T; } sort(lo0, lo); sort(lo == lo0 ? lo + 1 : lo, hi0); } /** eliminate duplicate lines */ void compress() { int limit = ncon; int c[] = con; sort(0, ncon - 1); int d = 0; int pp1 = -1; for (int i = 0; i < limit; i++) { int p1 = c[i]; if (pp1 != p1) { c[d] = p1; d++; } pp1 = p1; } ncon = d; } static Color gr[]; /** Paint this model to a graphics context. It uses the matrix associated with this model to map from model space to screen space. The next version of the browser should have double buffering, which will make this *much* nicer */ void paint(Graphics g) { if (vert == null || nvert <= 0) return; transform(); if (gr == null) { gr = new Color[16]; for (int i = 0; i < 16; i++) { int grey = (int) (100*Math.pow(i/15.0, 2.3)); gr[i] = new Color(grey, grey, grey); } } if (rob.megaSpeed) { paintWithoutDoubleBuffering(g); // is in netscape much faster return; } int lg = 0; int lim = ncon; int c[] = con; int v[] = tvert; if (lim <= 0 || nvert <= 0) return; Graphics offscreenG = offscreen.getGraphics();// for double-buffering offscreenG.setColor(new Color(200, 200, 200)); offscreenG.fillRect(0, 0, rob.canvasSize + 10, rob.canvasSize + 100); for (int i = 0; i < lim; i++) { int T = c[i]; int p1 = ((T >> 16) & 0xFFFF) * 3; int p2 = (T & 0xFFFF) * 3; int grey = v[p1 + 2] + v[p2 + 2]; if (grey < 0) grey = 0; if (grey > 15) grey = 15; if (grey != lg) { lg = grey; offscreenG.setColor(gr[grey]); } offscreenG.drawLine(v[p1], v[p1 + 1], v[p2], v[p2 + 1]); } String[] axisNames = { "x", "y", "z" }; for (int i = lim - 3; i < lim; i++) { // the axis names are painted int T = c[i]; int p1 = ((T >> 16) & 0xFFFF) * 3; int p2 = (T & 0xFFFF) * 3; int grey = v[p1 + 2] + v[p2 + 2]; if (grey < 0) grey = 0; if (grey > 15) grey = 15; if (grey != lg) { lg = grey; offscreenG.setColor(gr[grey]); } offscreenG.drawString(axisNames[i - lim + 3], v[p2], v[p2+1]); } g.drawImage(offscreen, 0, 0, rob.roboCanvas);// the completed image is // copied to the screen at once } void paintWithoutDoubleBuffering(Graphics g) { int lg = 0; int lim = ncon; int c[] = con; int v[] = tvert; if (lim <= 0 || nvert <= 0) return; g.setColor(new Color(200, 200, 200)); g.fillRect(0, 0, rob.canvasSize + 200, rob.canvasSize + 100); for (int i = 0; i < lim; i++) { int T = c[i]; int p1 = ((T >> 16) & 0xFFFF) * 3; int p2 = (T & 0xFFFF) * 3; int grey = v[p1 + 2] + v[p2 + 2]; if (grey < 0) grey = 0; if (grey > 15) grey = 15; if (grey != lg) { lg = grey; g.setColor(gr[grey]); } g.drawLine(v[p1], v[p1 + 1], v[p2], v[p2 + 1]); } String[] axisNames = { "x", "y", "z" }; for (int i = lim - 3; i < lim; i++) { // the axis names are painted int T = c[i]; int p1 = ((T >> 16) & 0xFFFF) * 3; int p2 = (T & 0xFFFF) * 3; int grey = v[p1 + 2] + v[p2 + 2]; if (grey < 0) grey = 0; if (grey > 15) grey = 15; if (grey != lg) { lg = grey; g.setColor(gr[grey]); } g.drawString(axisNames[i - lim + 3], v[p2], v[p2+1]); } } /** Find the bounding box of this model */ void findBB() { if (nvert <= 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 = nvert * 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; }}/** A class to put a 3D model into a page */class ThreeD implements Runnable { Canvas goalCanvas; // the wireframe gets painted into this canvas RoboProto rob; // 'rob' is needed as a reference for 'Model3D' Model3D md; boolean painted = true; float xfac; int prevx, prevy; float xtheta, ytheta; float axtheta = 0.0f, aytheta = 0.0f; float scalefudge = 0.5f; Matrix3D amat = new Matrix3D(), tmat = new Matrix3D(); String message = null; float f1 = 1, f2 = 1; //variables for the calculation of the scale factor public ThreeD(Canvas inCanvas, RoboProto dataRobot) { // the canvas has to be 500x500 pixels large goalCanvas = inCanvas; rob = dataRobot; axtheta = 21.0f; tmat.yrot(ytheta); tmat.xrot(axtheta); amat.mult(tmat); if (painted) { painted = false; this.repaint(); } } public void setScale(float newScale) { if (newScale > 0) { scalefudge = newScale; xfac = 0.7f * (f1 < f2 ? f1 : f2) * scalefudge; } } public void run() { try { Thread.currentThread().setPriority(Thread.MIN_PRIORITY); Model3D m = new Model3D (rob); md = m; m.findBB(); m.compress(); float xw = m.xmax - m.xmin; float yw = m.ymax - m.ymin; float zw = m.zmax - m.zmin; if (yw > xw) xw = yw; if (zw > xw) xw = zw; f1 = goalCanvas.size().width / xw; // the model gets adapted f2 = goalCanvas.size().height / xw;// to the canvas size xfac = 0.7f * (f1 < f2 ? f1 : f2) * scalefudge; } catch(Exception e) { md = null; message = e.toString(); } this.repaint(); } public void start() { if (md == null && message == null) { new Thread(this).start(); repaint(); } } public void stop() { } public void setVert(int no, Points newCoordinates){ if ((no >= 0) && (no < rob.numberOfPoints)) { md.vert[3 * no] = (float)newCoordinates.x; md.vert[3 * no + 1] = (float)newCoordinates.y; md.vert[3 * no + 2] = (float)newCoordinates.z; md.transformed = false; } } public boolean mouseDown(Event e, int x, int y) { prevx = x; prevy = y; return true; } public boolean mouseDrag(Event e, int x, int y) { tmat.unit(); float xtheta = (y - prevy) * 90.0f / goalCanvas.size().height; float ytheta = (prevx - x) * 180.0f / goalCanvas.size().width; tmat.xrot(-axtheta); if (axtheta + xtheta < 0.0) axtheta = 0.0f; else if (axtheta + xtheta > 90.0) axtheta = 90.0f; else axtheta += xtheta; tmat.yrot(ytheta); tmat.xrot(axtheta); amat.mult(tmat); if (painted) { painted = false; this.repaint(); } prevx = x; prevy = y; return true; } public void repaint() { this.paint(goalCanvas.getGraphics()); } public void paint(Graphics g) { // this g is the graphics of the canvas if (md != null) { md.mat.unit(); md.mat.translate(-(md.xmin + md.xmax) / 2, -(md.ymin + md.ymax) / 2, -(md.zmin + md.zmax) / 2); md.mat.mult(amat); md.mat.scale(xfac, -xfac, 16 * xfac / goalCanvas.size().width); md.mat.translate(goalCanvas.size().width / 2, goalCanvas.size().height / 2, 8); md.transformed = false; md.paint(g); setPainted(); } else if (message != null) { g.drawString("Error in model:", 3, 20); g.drawString(message, 10, 40); } } private synchronized void setPainted() { painted = true; notifyAll(); }}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -