Back to index

wims  3.65+svn20090927
ThreeD.java
Go to the documentation of this file.
00001 /*
00002  * @(#)TreeD.java
00003  *
00004  * Copyright (c) 1994-1996 Sun Microsystems, Inc. All Rights Reserved.
00005  *
00006  * Permission to use, copy, modify, and distribute this software
00007  * and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
00008  * without fee is hereby granted. 
00009  * Please refer to the file http://java.sun.com/copy_trademarks.html
00010  * for further important copyright and trademark information and to
00011  * http://java.sun.com/licensing.html for further important licensing
00012  * information for the Java (tm) Technology.
00013  * 
00014  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
00015  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
00016  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
00017  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
00018  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
00019  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
00020  * 
00021  * THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
00022  * CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
00023  * PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
00024  * NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
00025  * SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
00026  * SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
00027  * PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES").  SUN
00028  * SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
00029  * HIGH RISK ACTIVITIES.
00030  */
00031 /* A set of classes to parse, represent and display 3D wireframe models
00032    represented in Wavefront .obj format. */
00033 
00034 import java.applet.Applet;
00035 import java.awt.Graphics;
00036 import java.awt.Color;
00037 import java.awt.Event;
00038 import java.io.StreamTokenizer;
00039 import java.io.InputStream;
00040 import java.io.IOException;
00041 import java.net.URL;
00042 
00043 class FileFormatException extends Exception {
00044     public FileFormatException(String s) {
00045        super(s);
00046     }
00047 }
00048 
00050 class Model3D {
00051     float vert[];
00052     int tvert[];
00053     int nvert, maxvert;
00054     int con[];
00055     int ncon, maxcon;
00056     boolean transformed;
00057     Matrix3D mat;
00058 
00059     float xmin, xmax, ymin, ymax, zmin, zmax;
00060 
00061     Model3D () {
00062        mat = new Matrix3D ();
00063        mat.xrot(20);
00064        mat.yrot(30);
00065     }
00067     Model3D (InputStream is) throws IOException, FileFormatException {
00068        this();
00069        StreamTokenizer st = new StreamTokenizer(is);
00070        st.eolIsSignificant(true);
00071        st.commentChar('#');
00072 scan:
00073        while (true) {
00074            switch (st.nextToken()) {
00075              default:
00076               break scan;
00077              case StreamTokenizer.TT_EOL:
00078               break;
00079              case StreamTokenizer.TT_WORD:
00080               if ("v".equals(st.sval)) {
00081                   double x = 0, y = 0, z = 0;
00082                   if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
00083                      x = st.nval;
00084                      if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
00085                          y = st.nval;
00086                          if (st.nextToken() == StreamTokenizer.TT_NUMBER)
00087                             z = st.nval;
00088                      }
00089                   }
00090                   addVert((float) x, (float) y, (float) z);
00091                   while (st.ttype != StreamTokenizer.TT_EOL &&
00092                          st.ttype != StreamTokenizer.TT_EOF)
00093                      st.nextToken();
00094               } else if ("f".equals(st.sval) || "fo".equals(st.sval) || "l".equals(st.sval)) {
00095                   int start = -1;
00096                   int prev = -1;
00097                   int n = -1;
00098                   while (true)
00099                      if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
00100                          n = (int) st.nval;
00101                          if (prev >= 0)
00102                             add(prev - 1, n - 1);
00103                          if (start < 0)
00104                             start = n;
00105                          prev = n;
00106                      } else if (st.ttype == '/')
00107                          st.nextToken();
00108                      else
00109                          break;
00110                   if (start >= 0)
00111                      add(start - 1, prev - 1);
00112                   if (st.ttype != StreamTokenizer.TT_EOL)
00113                      break scan;
00114               } else {
00115                   while (st.nextToken() != StreamTokenizer.TT_EOL
00116                          && st.ttype != StreamTokenizer.TT_EOF);
00117               }
00118            }
00119        }
00120        is.close();
00121        if (st.ttype != StreamTokenizer.TT_EOF)
00122            throw new FileFormatException(st.toString());
00123     }
00124 
00126     int addVert(float x, float y, float z) {
00127        int i = nvert;
00128        if (i >= maxvert)
00129            if (vert == null) {
00130               maxvert = 100;
00131               vert = new float[maxvert * 3];
00132            } else {
00133               maxvert *= 2;
00134               float nv[] = new float[maxvert * 3];
00135               System.arraycopy(vert, 0, nv, 0, vert.length);
00136               vert = nv;
00137            }
00138        i *= 3;
00139        vert[i] = x;
00140        vert[i + 1] = y;
00141        vert[i + 2] = z;
00142        return nvert++;
00143     }
00145     void add(int p1, int p2) {
00146        int i = ncon;
00147        if (p1 >= nvert || p2 >= nvert)
00148            return;
00149        if (i >= maxcon)
00150            if (con == null) {
00151               maxcon = 100;
00152               con = new int[maxcon];
00153            } else {
00154               maxcon *= 2;
00155               int nv[] = new int[maxcon];
00156               System.arraycopy(con, 0, nv, 0, con.length);
00157               con = nv;
00158            }
00159        if (p1 > p2) {
00160            int t = p1;
00161            p1 = p2;
00162            p2 = t;
00163        }
00164        con[i] = (p1 << 16) | p2;
00165        ncon = i + 1;
00166     }
00168     void transform() {
00169        if (transformed || nvert <= 0)
00170            return;
00171        if (tvert == null || tvert.length < nvert * 3)
00172            tvert = new int[nvert*3];
00173        mat.transform(vert, tvert, nvert);
00174        transformed = true;
00175     }
00176 
00177    /* Quick Sort implementation
00178     */
00179    private void quickSort(int a[], int left, int right)
00180    {
00181       int leftIndex = left;
00182       int rightIndex = right;
00183       int partionElement;
00184       if ( right > left)
00185       {
00186 
00187          /* Arbitrarily establishing partition element as the midpoint of
00188           * the array.
00189           */
00190          partionElement = a[ ( left + right ) / 2 ];
00191 
00192          // loop through the array until indices cross
00193          while( leftIndex <= rightIndex )
00194          {
00195             /* find the first element that is greater than or equal to 
00196              * the partionElement starting from the leftIndex.
00197              */
00198             while( ( leftIndex < right ) && ( a[leftIndex] < partionElement ) )
00199                ++leftIndex;
00200 
00201             /* find an element that is smaller than or equal to 
00202              * the partionElement starting from the rightIndex.
00203              */
00204             while( ( rightIndex > left ) && 
00205                    ( a[rightIndex] > partionElement ) )
00206                --rightIndex;
00207 
00208             // if the indexes have not crossed, swap
00209             if( leftIndex <= rightIndex ) 
00210             {
00211                swap(a, leftIndex, rightIndex);
00212                ++leftIndex;
00213                --rightIndex;
00214             }
00215          }
00216 
00217          /* If the right index has not reached the left side of array
00218           * must now sort the left partition.
00219           */
00220          if( left < rightIndex )
00221             quickSort( a, left, rightIndex );
00222 
00223          /* If the left index has not reached the right side of array
00224           * must now sort the right partition.
00225           */
00226          if( leftIndex < right )
00227             quickSort( a, leftIndex, right );
00228 
00229       }
00230    }
00231 
00232    private void swap(int a[], int i, int j)
00233    {
00234       int T;
00235       T = a[i]; 
00236       a[i] = a[j];
00237       a[j] = T;
00238    }
00239 
00240 
00242     void compress() {
00243        int limit = ncon;
00244        int c[] = con;
00245        quickSort(con, 0, ncon - 1);
00246        int d = 0;
00247        int pp1 = -1;
00248        for (int i = 0; i < limit; i++) {
00249            int p1 = c[i];
00250            if (pp1 != p1) {
00251               c[d] = p1;
00252               d++;
00253            }
00254            pp1 = p1;
00255        }
00256        ncon = d;
00257     }
00258 
00259     static Color gr[];
00260 
00265     void paint(Graphics g) {
00266        if (vert == null || nvert <= 0)
00267            return;
00268        transform();
00269        if (gr == null) {
00270            gr = new Color[16];
00271            for (int i = 0; i < 16; i++) {
00272               int grey = (int) (170*(1-Math.pow(i/15.0, 2.3)));
00273               gr[i] = new Color(grey, grey, grey);
00274            }
00275        }
00276        int lg = 0;
00277        int lim = ncon;
00278        int c[] = con;
00279        int v[] = tvert;
00280        if (lim <= 0 || nvert <= 0)
00281            return;
00282        for (int i = 0; i < lim; i++) {
00283            int T = c[i];
00284            int p1 = ((T >> 16) & 0xFFFF) * 3;
00285            int p2 = (T & 0xFFFF) * 3;
00286            int grey = v[p1 + 2] + v[p2 + 2];
00287            if (grey < 0)
00288               grey = 0;
00289            if (grey > 15)
00290               grey = 15;
00291            if (grey != lg) {
00292               lg = grey;
00293               g.setColor(gr[grey]);
00294            }
00295            g.drawLine(v[p1], v[p1 + 1],
00296                      v[p2], v[p2 + 1]);
00297        }
00298     }
00299 
00301     void findBB() {
00302        if (nvert <= 0)
00303            return;
00304        float v[] = vert;
00305        float xmin = v[0], xmax = xmin;
00306        float ymin = v[1], ymax = ymin;
00307        float zmin = v[2], zmax = zmin;
00308        for (int i = nvert * 3; (i -= 3) > 0;) {
00309            float x = v[i];
00310            if (x < xmin)
00311               xmin = x;
00312            if (x > xmax)
00313               xmax = x;
00314            float y = v[i + 1];
00315            if (y < ymin)
00316               ymin = y;
00317            if (y > ymax)
00318               ymax = y;
00319            float z = v[i + 2];
00320            if (z < zmin)
00321               zmin = z;
00322            if (z > zmax)
00323               zmax = z;
00324        }
00325        this.xmax = xmax;
00326        this.xmin = xmin;
00327        this.ymax = ymax;
00328        this.ymin = ymin;
00329        this.zmax = zmax;
00330        this.zmin = zmin;
00331     }
00332 }
00333 
00335 public class ThreeD extends Applet implements Runnable {
00336     Model3D md;
00337     boolean painted = true;
00338     float xfac;
00339     int prevx, prevy;
00340     float xtheta, ytheta;
00341     float scalefudge = 1;
00342     Matrix3D amat = new Matrix3D(), tmat = new Matrix3D();
00343     String mdname = null;
00344     String message = null;
00345 
00346     public void init() {
00347        mdname = getParameter("model");
00348        try {
00349            scalefudge = Float.valueOf(getParameter("scale")).floatValue();
00350        }catch(Exception e){};
00351        amat.yrot(20);
00352        amat.xrot(20);
00353        if (mdname == null)
00354            mdname = "model.obj";
00355        resize(size().width <= 20 ? 400 : size().width,
00356               size().height <= 20 ? 400 : size().height);
00357     }
00358     public void run() {
00359        InputStream is = null;
00360        try {
00361            Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
00362            is = new URL(getDocumentBase(), mdname).openStream();
00363            Model3D m = new Model3D (is);
00364            md = m;
00365            m.findBB();
00366            m.compress();
00367            float xw = m.xmax - m.xmin;
00368            float yw = m.ymax - m.ymin;
00369            float zw = m.zmax - m.zmin;
00370            if (yw > xw)
00371               xw = yw;
00372            if (zw > xw)
00373               xw = zw;
00374            float f1 = size().width / xw;
00375            float f2 = size().height / xw;
00376            xfac = 0.7f * (f1 < f2 ? f1 : f2) * scalefudge;
00377        } catch(Exception e) {
00378            md = null;
00379            message = e.toString();
00380        }
00381        try {
00382            if (is != null)
00383               is.close();
00384        } catch(Exception e) {
00385        }
00386        repaint();
00387     }
00388     public void start() {
00389        if (md == null && message == null)
00390            new Thread(this).start();
00391     }
00392     public void stop() {
00393     }
00394     public boolean mouseDown(Event e, int x, int y) {
00395        prevx = x;
00396        prevy = y;
00397        return true;
00398     }
00399     public boolean mouseDrag(Event e, int x, int y) {
00400        tmat.unit();
00401        float xtheta = (prevy - y) * 360.0f / size().width;
00402        float ytheta = (x - prevx) * 360.0f / size().height;
00403        tmat.xrot(xtheta);
00404        tmat.yrot(ytheta);
00405        amat.mult(tmat);
00406        if (painted) {
00407            painted = false;
00408            repaint();
00409        }
00410        prevx = x;
00411        prevy = y;
00412        return true;
00413     }
00414     public void paint(Graphics g) {
00415        if (md != null) {
00416            md.mat.unit();
00417            md.mat.translate(-(md.xmin + md.xmax) / 2,
00418                           -(md.ymin + md.ymax) / 2,
00419                           -(md.zmin + md.zmax) / 2);
00420            md.mat.mult(amat);
00421 //         md.mat.scale(xfac, -xfac, 8 * xfac / size().width);
00422            md.mat.scale(xfac, -xfac, 16 * xfac / size().width);
00423            md.mat.translate(size().width / 2, size().height / 2, 8);
00424            md.transformed = false;
00425            md.paint(g);
00426            setPainted();
00427        } else if (message != null) {
00428            g.drawString("Error in model:", 3, 20);
00429            g.drawString(message, 10, 40);
00430        }
00431     }
00432     private synchronized void setPainted() {
00433        painted = true;
00434        notifyAll();
00435     }
00436 //    private synchronized void waitPainted() {
00437 //     while (!painted)
00438 //         wait();
00439 //     painted = false;
00440 //    }
00441 }