KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > JSci > swing > JLineGraph3D


1 package JSci.swing;
2
3 import java.awt.*;
4 import java.awt.event.*;
5 import javax.swing.*;
6 import java.util.Arrays JavaDoc;
7
8 import JSci.awt.*;
9
10 /**
11 * A 3D line graph Swing component.
12 * @author Daniel Lemire
13 */

14 public final class JLineGraph3D extends JDoubleBufferedComponent
15   implements Runnable JavaDoc, MouseListener, MouseMotionListener, GraphDataListener {
16
17     protected Graph3DModel model;
18     private Model3D md;
19     private boolean painted = true;
20     private float xfac;
21     private int prevx, prevy;
22     private float xtheta, ytheta;
23     private float scalefudge = 1.0f;
24     private Matrix3D amat = new Matrix3D();
25     private Matrix3D tmat = new Matrix3D();
26     private String JavaDoc mdname = null;
27     private String JavaDoc message = null;
28
29         /**
30         * Constructs a 3D line graph.
31         */

32     public JLineGraph3D(Graph3DModel data) {
33       amat.yRotate(20);
34       amat.xRotate(20);
35       setSize(getWidth() <= 20 ? 400 : getWidth(),
36              getHeight() <= 20 ? 400 : getHeight());
37       addMouseListener(this);
38       addMouseMotionListener(this);
39       setModel(data);
40     }
41
42
43     /**
44     * Sets the data plotted by this graph to the specified data.
45     */

46     public void setModel(Graph3DModel gm) {
47             if(model!=null)
48               model.removeGraphDataListener(this);
49             model=gm;
50             model.addGraphDataListener(this);
51             dataChanged(new GraphDataEvent(model));
52     }
53
54         /**
55         * Implementation of GraphDataListener.
56         * Application code will not use this method explicitly, it is used internally.
57         */

58     public void dataChanged(GraphDataEvent e) {
59       md=new Model3D();
60       model.firstSeries();
61       for(int k=0;k<model.seriesLength();k++) {
62         md.addVertex(model.getXCoord(k),model.getYCoord(k),model.getZCoord(k));
63       }
64       for(int k=1;k<model.seriesLength();k++) {
65         md.addLine(k-1,k);
66       }
67       redraw();
68       new Thread JavaDoc(this).start();
69     }
70
71     public void run() {
72       try {
73           md.findBoundingBox();
74           md.compress();
75           float xw = md.xmax - md.xmin;
76           float yw = md.ymax - md.ymin;
77           float zw = md.zmax - md.zmin;
78           if (yw > xw)
79         xw = yw;
80           if (zw > xw)
81         xw = zw;
82           float f1 = getWidth() / xw;
83           float f2 = getHeight() / xw;
84           xfac = 0.7f * (f1 < f2 ? f1 : f2) * scalefudge;
85       } catch(Exception JavaDoc e) {
86           md = null;
87           message = e.toString();
88           e.printStackTrace();
89       }
90         repaint();
91     }
92
93     public void mouseClicked(MouseEvent e) {
94     }
95
96     public void mousePressed(MouseEvent e) {
97         prevx = e.getX();
98         prevy = e.getY();
99         e.consume();
100     }
101
102     public void mouseReleased(MouseEvent e) {
103     }
104
105     public void mouseEntered(MouseEvent e) {
106     }
107
108     public void mouseExited(MouseEvent e) {
109     }
110
111     public void mouseDragged(MouseEvent e) {
112       int x = e.getX();
113       int y = e.getY();
114       if((e.getModifiers() & MouseEvent.BUTTON3_MASK)!=0) {
115         if(prevy==y)
116           return; //don't need to do anything
117
scalefudge+=(prevy-y)/(float)getWidth();
118         if(scalefudge==0)
119           scalefudge=0.1f;//arbitrary
120
float xw = md.xmax - md.xmin;
121         float yw = md.ymax - md.ymin;
122         float zw = md.zmax - md.zmin;
123         if (yw > xw)
124           xw = yw;
125         if (zw > xw)
126           xw = zw;
127         float f1 = getWidth() / xw;
128         float f2 = getHeight() / xw;
129         xfac = 0.7f * (f1 < f2 ? f1 : f2) * scalefudge;
130
131       }
132       if((e.getModifiers() & MouseEvent.BUTTON1_MASK)!=0) {
133           tmat.identity();
134           float xtheta = (prevy - y) * 360.0f / getWidth();
135           float ytheta = (x - prevx) * 360.0f / getHeight();
136           tmat.xRotate(xtheta);
137           tmat.yRotate(ytheta);
138           amat.multiply(tmat);
139       }
140       if (painted) {
141           painted = false;
142           redraw();
143       }
144       prevx = x;
145       prevy = y;
146       e.consume();
147
148     }
149
150     public void mouseMoved(MouseEvent e) {
151     }
152         /**
153         * Paint the graph.
154         */

155         protected void offscreenPaint(Graphics g) {
156                 if (md != null) {
157 // System.out.println("painting");
158
md.mat.identity();
159                         md.mat.translate(-(md.xmin + md.xmax) / 2,
160                                 -(md.ymin + md.ymax) / 2,
161                                 -(md.zmin + md.zmax) / 2);
162                         md.mat.multiply(amat);
163                         md.mat.scale(xfac, -xfac, 16 * xfac / getWidth());
164                         md.mat.translate(getWidth() / 2, getHeight() / 2, 8);
165                         md.transformed = false;
166                         md.paint(g);
167 // System.out.println("painting done");
168
setPainted();
169                 } else if (message != null) {
170                         g.drawString("Error in model:", 3, 20);
171                         g.drawString(message, 10, 40);
172                 }
173         }
174         /**
175         * Returns the preferred size of this component.
176         */

177         public Dimension getPreferredSize() {
178                 return getMinimumSize();
179         }
180         /**
181         * Returns the minimum size of this component.
182         */

183         public Dimension getMinimumSize() {
184                 return new Dimension(400,400);
185         }
186
187     private synchronized void setPainted() {
188         painted = true;
189         notifyAll();
190     }
191 }
192
193 class Model3D {
194         private static Color greys[];
195         float vert[];
196         int tvert[];
197         int nvert, maxvert;
198         int con[];
199         int ncon, maxcon;
200         boolean transformed;
201         Matrix3D mat;
202         float xmin, xmax, ymin, ymax, zmin, zmax;
203         private float axes[]=new float[18];
204         private int taxes[]=new int[18];
205
206         static {
207                 greys=new Color[16];
208                 int gr;
209                 for(int i=0;i<greys.length;i++) {
210                         gr=(int)(170.0*(1.0-Math.pow(i/15.0,2.3)));
211                         greys[i]=new Color(gr,gr,gr);
212                 }
213         }
214
215     Model3D() {
216     mat = new Matrix3D();
217     mat.xRotate(20);
218     mat.yRotate(30);
219     }
220
221
222     /** Add a vertex to this model */
223     int addVertex(float x, float y, float z) {
224     int i = nvert;
225     if (i >= maxvert)
226         if (vert == null) {
227         maxvert = 100;
228         vert = new float[maxvert * 3];
229         } else {
230         maxvert *= 2;
231         float nv[] = new float[maxvert * 3];
232         System.arraycopy(vert, 0, nv, 0, vert.length);
233         vert = nv;
234         }
235     i *= 3;
236     vert[i] = x;
237     vert[i + 1] = y;
238     vert[i + 2] = z;
239 // System.out.println("added a vertex "+nvert);
240
return nvert++;
241     }
242     /** Add a line from vertex p1 to vertex p2 */
243     void addLine(int p1, int p2) {
244     int i = ncon;
245     if (p1 >= nvert || p2 >= nvert) {
246 // System.out.println("Line from "+p1+" to "+p2+" will not be drawn. ("+nvert+")");
247
return;
248   }
249     if (i >= maxcon)
250         if (con == null) {
251         maxcon = 100;
252         con = new int[maxcon];
253         } else {
254         maxcon *= 2;
255         int nv[] = new int[maxcon];
256         System.arraycopy(con, 0, nv, 0, con.length);
257         con = nv;
258         }
259     if (p1 > p2) {
260         int t = p1;
261         p1 = p2;
262         p2 = t;
263     }
264     con[i] = (p1 << 16) | p2;
265     ncon = i + 1;
266     }
267     /** Transform all the points in this model */
268     void transform() {
269     if (transformed || nvert <= 0)
270         return;
271         mat.transform(axes,taxes,6);
272     if (tvert == null || tvert.length < nvert * 3)
273         tvert = new int[nvert*3];
274     mat.transform(vert, tvert, nvert);
275     transformed = true;
276     }
277
278     /** eliminate duplicate lines */
279     void compress() {
280     int limit = ncon;
281     int c[] = con;
282     Arrays.sort(con, 0, ncon);
283     int d = 0;
284     int pp1 = -1;
285     for (int i = 0; i < limit; i++) {
286         int p1 = c[i];
287         if (pp1 != p1) {
288         c[d] = p1;
289         d++;
290         }
291         pp1 = p1;
292     }
293     ncon = d;
294     }
295
296     void paint(Graphics g) {
297 // System.out.println("painting model 3D");
298

299         if (vert == null || nvert <= 0)
300           return;
301         transform();
302         Color lastGrey=null;
303         int lim = ncon;
304         int c[] = con;
305         int v[] = tvert;
306 // System.out.println(lim+" "+nvert);
307
if (lim <= 0 || nvert <= 0)
308           return;
309 // draw axes
310
int a[]=taxes;
311                 g.setColor(depthColor(a[2],a[5]));
312                 g.drawLine(a[0],a[1],a[3],a[4]);
313                 g.setColor(depthColor(a[8],a[11]));
314                 g.drawLine(a[6],a[7],a[9],a[10]);
315                 g.setColor(depthColor(a[14],a[17]));
316                 g.drawLine(a[12],a[13],a[15],a[16]);
317 // draw points
318
int T,p1,p2;
319                 Color grey;
320         for (int i = 0; i < lim; i++) {
321           T = c[i];
322           p1 = ((T >> 16) & 0xFFFF) * 3;
323           p2 = (T & 0xFFFF) * 3;
324           grey=depthColor(v[p1+2],v[p2+2]);
325           if (grey != lastGrey) {
326               lastGrey = grey;
327               g.setColor(grey);
328           }
329 // System.out.println("drawing line "+v[p1]+" "+v[p1 + 1]+" "+v[p2]+" "+v[p2 + 1]);
330
g.drawLine(v[p1], v[p1 + 1],v[p2], v[p2 + 1]);
331         }
332     }
333         /**
334         * Converts z coordinates to shades of grey.
335         * @param z1 z coord of start of line.
336         * @param z2 z coord of end of line.
337         */

338         private Color depthColor(int z1,int z2) {
339                 int gr=z1+z2;
340                 if(gr<0)
341                         gr=0;
342                 else if(gr>15)
343                         gr=15;
344                 return greys[gr];
345         }
346
347     /** Find the bounding box of this model */
348     void findBoundingBox() {
349     if (nvert <= 0)
350         return;
351     float v[] = vert;
352     float xmin = v[0], xmax = xmin;
353     float ymin = v[1], ymax = ymin;
354     float zmin = v[2], zmax = zmin;
355     for (int i = nvert * 3; (i -= 3) > 0;) {
356         float x = v[i];
357         if (x < xmin)
358         xmin = x;
359         if (x > xmax)
360         xmax = x;
361         float y = v[i + 1];
362         if (y < ymin)
363         ymin = y;
364         if (y > ymax)
365         ymax = y;
366         float z = v[i + 2];
367         if (z < zmin)
368         zmin = z;
369         if (z > zmax)
370         zmax = z;
371     }
372     this.xmax = xmax;
373     this.xmin = xmin;
374     this.ymax = ymax;
375     this.ymin = ymin;
376     this.zmax = zmax;
377     this.zmin = zmin;
378         axes[0]=xmax;
379         axes[3]=xmin;
380         axes[7]=ymax;
381         axes[10]=ymin;
382         axes[14]=zmax;
383         axes[17]=zmin;
384     }
385 }
386
387 class Matrix3D {
388     float xx, xy, xz, xo;
389     float yx, yy, yz, yo;
390     float zx, zy, zz, zo;
391     /** Create a new identity matrix */
392     Matrix3D () {
393     xx = 1.0f;
394     yy = 1.0f;
395     zz = 1.0f;
396     }
397     /** Scale by f in all dimensions */
398     void scale(float f) {
399     xx *= f;
400     xy *= f;
401     xz *= f;
402     xo *= f;
403     yx *= f;
404     yy *= f;
405     yz *= f;
406     yo *= f;
407     zx *= f;
408     zy *= f;
409     zz *= f;
410     zo *= f;
411     }
412     /** Scale along each axis independently */
413     void scale(float xf, float yf, float zf) {
414     xx *= xf;
415     xy *= xf;
416     xz *= xf;
417     xo *= xf;
418     yx *= yf;
419     yy *= yf;
420     yz *= yf;
421     yo *= yf;
422     zx *= zf;
423     zy *= zf;
424     zz *= zf;
425     zo *= zf;
426     }
427     /** Translate the origin */
428     void translate(float x, float y, float z) {
429     xo += x;
430     yo += y;
431     zo += z;
432     }
433     /** rotate theta degrees about the y axis */
434     void yRotate(double theta) {
435     theta *= (Math.PI / 180.0);
436     double ct = Math.cos(theta);
437     double st = Math.sin(theta);
438
439     float Nxx = (float) (xx * ct + zx * st);
440     float Nxy = (float) (xy * ct + zy * st);
441     float Nxz = (float) (xz * ct + zz * st);
442     float Nxo = (float) (xo * ct + zo * st);
443
444     float Nzx = (float) (zx * ct - xx * st);
445     float Nzy = (float) (zy * ct - xy * st);
446     float Nzz = (float) (zz * ct - xz * st);
447     float Nzo = (float) (zo * ct - xo * st);
448
449     xo = Nxo;
450     xx = Nxx;
451     xy = Nxy;
452     xz = Nxz;
453     zo = Nzo;
454     zx = Nzx;
455     zy = Nzy;
456     zz = Nzz;
457     }
458     /** rotate theta degrees about the x axis */
459     void xRotate(double theta) {
460     theta *= (Math.PI / 180.0);
461     double ct = Math.cos(theta);
462     double st = Math.sin(theta);
463
464     float Nyx = (float) (yx * ct + zx * st);
465     float Nyy = (float) (yy * ct + zy * st);
466     float Nyz = (float) (yz * ct + zz * st);
467     float Nyo = (float) (yo * ct + zo * st);
468
469     float Nzx = (float) (zx * ct - yx * st);
470     float Nzy = (float) (zy * ct - yy * st);
471     float Nzz = (float) (zz * ct - yz * st);
472     float Nzo = (float) (zo * ct - yo * st);
473
474     yo = Nyo;
475     yx = Nyx;
476     yy = Nyy;
477     yz = Nyz;
478     zo = Nzo;
479     zx = Nzx;
480     zy = Nzy;
481     zz = Nzz;
482     }
483     /** rotate theta degrees about the z axis */
484     void zRotate(double theta) {
485     theta *= (Math.PI / 180.0);
486     double ct = Math.cos(theta);
487     double st = Math.sin(theta);
488
489     float Nyx = (float) (yx * ct + xx * st);
490     float Nyy = (float) (yy * ct + xy * st);
491     float Nyz = (float) (yz * ct + xz * st);
492     float Nyo = (float) (yo * ct + xo * st);
493
494     float Nxx = (float) (xx * ct - yx * st);
495     float Nxy = (float) (xy * ct - yy * st);
496     float Nxz = (float) (xz * ct - yz * st);
497     float Nxo = (float) (xo * ct - yo * st);
498
499     yo = Nyo;
500     yx = Nyx;
501     yy = Nyy;
502     yz = Nyz;
503     xo = Nxo;
504     xx = Nxx;
505     xy = Nxy;
506     xz = Nxz;
507     }
508     /** Multiply this matrix by a second: M = M*R */
509     void multiply(Matrix3D rhs) {
510     float lxx = xx * rhs.xx + yx * rhs.xy + zx * rhs.xz;
511     float lxy = xy * rhs.xx + yy * rhs.xy + zy * rhs.xz;
512     float lxz = xz * rhs.xx + yz * rhs.xy + zz * rhs.xz;
513     float lxo = xo * rhs.xx + yo * rhs.xy + zo * rhs.xz + rhs.xo;
514
515     float lyx = xx * rhs.yx + yx * rhs.yy + zx * rhs.yz;
516     float lyy = xy * rhs.yx + yy * rhs.yy + zy * rhs.yz;
517     float lyz = xz * rhs.yx + yz * rhs.yy + zz * rhs.yz;
518     float lyo = xo * rhs.yx + yo * rhs.yy + zo * rhs.yz + rhs.yo;
519
520     float lzx = xx * rhs.zx + yx * rhs.zy + zx * rhs.zz;
521     float lzy = xy * rhs.zx + yy * rhs.zy + zy * rhs.zz;
522     float lzz = xz * rhs.zx + yz * rhs.zy + zz * rhs.zz;
523     float lzo = xo * rhs.zx + yo * rhs.zy + zo * rhs.zz + rhs.zo;
524
525     xx = lxx;
526     xy = lxy;
527     xz = lxz;
528     xo = lxo;
529
530     yx = lyx;
531     yy = lyy;
532     yz = lyz;
533     yo = lyo;
534
535     zx = lzx;
536     zy = lzy;
537     zz = lzz;
538     zo = lzo;
539     }
540
541     /** Reinitialize to the identity matrix */
542     void identity() {
543     xo = 0;
544     xx = 1;
545     xy = 0;
546     xz = 0;
547     yo = 0;
548     yx = 0;
549     yy = 1;
550     yz = 0;
551     zo = 0;
552     zx = 0;
553     zy = 0;
554     zz = 1;
555     }
556     /** Transform nvert points from v into tv. v contains the input
557         coordinates in floating point. Three successive entries in
558     the array constitute a point. tv ends up holding the transformed
559     points as integers; three successive entries per point */

560     void transform(float v[], int tv[], int nvert) {
561     float lxx = xx, lxy = xy, lxz = xz, lxo = xo;
562     float lyx = yx, lyy = yy, lyz = yz, lyo = yo;
563     float lzx = zx, lzy = zy, lzz = zz, lzo = zo;
564     for (int i = nvert * 3; (i -= 3) >= 0;) {
565         float x = v[i];
566         float y = v[i + 1];
567         float z = v[i + 2];
568         tv[i ] = (int) (x * lxx + y * lxy + z * lxz + lxo);
569         tv[i + 1] = (int) (x * lyx + y * lyy + z * lyz + lyo);
570         tv[i + 2] = (int) (x * lzx + y * lzy + z * lzz + lzo);
571     }
572     }
573     public String JavaDoc toString() {
574     return ("[" + xo + "," + xx + "," + xy + "," + xz + ";"
575         + yo + "," + yx + "," + yy + "," + yz + ";"
576         + zo + "," + zx + "," + zy + "," + zz + "]");
577     }
578 }
579
580
Popular Tags