Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: jplot/Graph_Piper.java


1   /*
2    * JPLOT  -- Java Plotting Interface for any programme or
3    *           as an independent GUI
4    * 
5    * Copyright (C) 1999 Jan van der Lee
6    *
7    * This program is free software; you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation; either version 2
10   * of the License, or (at your option) any later version.
11   *
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.
16   * 
17   * You should have received a copy of the GNU General Public License
18   * along with this program; if not, write to the Free Software
19   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
20   * 02111-1307, USA.
21   *
22   * Send bugs, suggestions or queries to <jplot@cig.ensmp.fr>
23   * The latest releases are found at 
24   * http://www.cig.ensmp.fr/~vanderlee/jplot.html
25   *
26   * Initally developed for use by the Centre d'Informatique Geologique 
27   * Ecole des Mines de Paris, Fontainebleau, France.
28   */
29  
30  package jplot;
31  
32  import javax.swing.*;
33  import java.awt.*;
34  import java.awt.image.*;
35  import java.text.*;
36  import java.math.*;
37  import java.awt.geom.*;
38  import java.awt.event.*;
39  import javax.swing.border.*;
40  import java.util.*;
41  import java.awt.print.*;
42  
43  /**
44   * The <code>Graph_Piper</code> class builds a panel which displays a
45   * Piper-diagram (ask geochemists what this is) according to the data 
46   * stored in the {@link DataArray}.
47   * All general graph stuff and initialization is done in class
48   * <code>Graph</code>.
49   *
50   * @version 24/08/99
51   * @author  J. van der Lee
52   */
53  public class Graph_Piper extends Graph {
54  
55    // handy variables
56    private final double sin30 = Math.sin(Math.PI/6.0);
57  
58    /**
59     * Main constructor.
60     * @param jp current jplot instance
61     * @param gp objects containing the parameters used to draw this graph.
62     */
63    public Graph_Piper(JPlot jp, GraphPars gp) {
64      super(jp,gp);
65      if (JPlot.debug) System.out.print("Initializing piper diagram...");
66      piperSep = 20.0;
67      gp.setBoxOffset(10.0f);
68      gp.setShowBox(true);
69      normalSep = piperSep*Math.sin(Math.PI/3);
70      gp.setMaxValue(X,100);
71      gp.setMinValue(X,0);
72      gp.setMaxValue(Y,100);
73      gp.setMinValue(Y,0);
74      numberOfTics[X] = 6;
75      numberOfTics[Y] = 6;
76      GraphLabel gl = new GraphLabel(GraphLabel.PIPER_X1,"Ca[2+]",
77             gp.getTicFont(X),Color.black);
78      gp.addLabel(gl);
79      gl = new GraphLabel(GraphLabel.PIPER_X2,"Cl[-]",
80        gp.getTicFont(X),Color.black);
81      gp.addLabel(gl);
82      gl = new GraphLabel(GraphLabel.PIPER_Y1,"Mg[2+]",
83        gp.getTicFont(Y),Color.black);
84      gp.addLabel(gl);
85      gl = new GraphLabel(GraphLabel.PIPER_Y2,"SO4[2-]",
86        gp.getTicFont(Y),Color.black);
87      gp.addLabel(gl);
88      gl = new GraphLabel(GraphLabel.PIPER_Y3,"Cl[-] + SO4[2-]",
89        gp.getTicFont(Y),Color.black);
90      gp.addLabel(gl);
91      gl = new GraphLabel(GraphLabel.PIPER_Y4,"Ca[2+] + Mg[2+]",
92        gp.getTicFont(Y),Color.black);
93      gp.addLabel(gl);
94      if (JPlot.debug) System.out.println("done.");
95    }
96  
97    /*
98     * Makes a set of defaults labels which are set around the axes.
99     */
100   private void makeDefaultLabels() {
101   }
102 
103   /**
104    * Determine the axis labels, if needed. These are numbers
105    * which are translated in Strings. The length is evalulated
106    * and used to set the left and bottom margins.
107    */
108   protected void makeTicLabels() {
109     double f, Xn, Yn;
110     final int numDigits = 4;
111 
112     // make the X-axis labels:
113     //------------------------
114     if (gp.drawTicLabels(X)) {
115       Xn = (gp.getMaxValue(X)-gp.getMinValue(X))/(numberOfTics[X]-1);
116       if (JPlot.debug) System.out.print("\nXlabels:");
117       for (int i=0; i<numberOfTics[X]; i++) {
118   f = gp.getMinValue(X)+i*Xn;
119   if (JPlot.debug) System.out.print(" " + f);
120   ticLabel[X][i] = formatNumber(f,numDigits);
121       }
122     }
123 
124     // make the Y axes labels:
125     //------------------------    
126     if (gp.drawTicLabels(Y)) {
127       Yn = (gp.getMaxValue(Y)-gp.getMinValue(Y))/(numberOfTics[Y]-1);
128       if (JPlot.debug) System.out.print("\nYlabels:");
129       for (int i=0; i<numberOfTics[Y]; i++) {
130   f = gp.getMinValue(Y)+Yn*i;
131   if (JPlot.debug) System.out.print(" " + f);
132   ticLabel[Y][i] = formatNumber(f,numDigits);
133       }
134       if (JPlot.debug) System.out.println();
135     }    
136   }
137 
138   /**
139    * This function draws the tics on the axis.
140    * Quite complex job for piper diagrams...
141    * @param g2 instance of the graphical canvas
142    */
143   private void drawTics(Graphics2D g2) {
144     double x2,y2,x1, y1 = topMargin + axisLength[Y];
145     
146     // draw the X-tics in the lower two triangles:
147     if (gp.drawTics(X)) {
148       for (int i=1; i<numberOfTics[X]-1; i++) {
149   x1 = leftMargin + sep[X]*i;
150   x2 = x1-cos*ticLength[X];
151   y2 = y1-sin*ticLength[X];
152   line.setLine(x1,y1,x2,y2);
153   g2.draw(line);
154   x1 += triangleBottom+piperSep;
155   x2 = x1+cos*ticLength[X];
156   y2 = y1-sin*ticLength[X];
157   line.setLine(x1,y1,x2,y2);
158   g2.draw(line);
159       }
160     }
161     // draw the Y-tics in the lower two triangles:
162     if (gp.drawTics(Y)) {
163       y1 = topMargin + axisLength[Y];
164       for (int i=1; i<numberOfTics[Y]-1; i++) {
165   x1 = leftMargin + sep[X]*i/2.0;
166   x2 = x1 + ticLength[Y];
167   y1 -= sep[Y];
168   line.setLine(x1,y1,x2,y1);
169   g2.draw(line);
170   x1 = leftMargin + axisLength[X] - sep[X]*i/2.0;
171   x2 = x1 - ticLength[Y];
172   line.setLine(x1,y1,x2,y1);
173   g2.draw(line);
174       }
175     }
176   }
177 
178   /**
179    * This function draws the grid.
180    * @param g2 instance of the graphical canvas
181    */
182   private void drawGrid(Graphics2D g2) {
183     double x2,y2,x1, y1 = topMargin + axisLength[Y];
184     g2.setColor(gp.getGridColor());
185     
186     // draw the X-grid lines in the lower two triangles:
187     if (gp.drawGrid(X) || gp.drawGrid(Y)) {
188       for (int j=0; j<2; j++) {  
189   double offset = (triangleBottom+piperSep)*j + leftMargin;
190   for (int i=1; i<numberOfTics[X]-1; i++) {
191     x1 = offset + sep[X]*i;
192     x2 = x1+(triangleBottom-sep[X]*i)/2.0;
193     y2 = y1-(triangleHeight-sep[Y]*i);
194     if (gp.drawGrid(X)) {
195       line.setLine(x1,y1,x2,y2);
196       g2.draw(line);
197     }
198     x1 = x2-sep[X]*i;
199     if (gp.drawGrid(Y)) {
200       line.setLine(x2,y2,x1,y2);
201       g2.draw(line);
202     }
203     x2 = offset + triangleBottom - sep[X]*i;
204     if (gp.drawGrid(X)) {
205       line.setLine(x1,y2,x2,y1);
206       g2.draw(line);
207     }
208   }
209       }
210     }
211 
212     if (gp.drawGrid(X)) {
213       // draw the grid in the upper area:
214       double sign=1.0;
215       for (int j=0; j<2; j++) {
216   y1 = topMargin + axisLength[Y] - normalSep;
217   if (j == 1) sign = -1.0;
218   for (int i=1; i<numberOfTics[X]-1; i++) {
219     x1 = leftMargin + triangleBottom + piperSep/2 - sign*sin30*sep[X]*i;
220     //x1 = leftMargin + triangleBottom + piperSep/2 - sign*sin*sep[X]*i;
221     y1 -= sep[Y];
222     x2 = x1 + sign*triangleBottom/2;
223     y2 = y1-triangleHeight;
224     line.setLine(x1,y1,x2,y2);
225     g2.draw(line);
226   }
227       }
228     }
229   }
230 
231   /*
232    * Draws a colored, filled triangle in each triangle.
233    * Used to quickly check whether the points are centered.
234    */
235   private void drawFilledTriangles(Graphics2D g2) {
236     double xOffset;
237     // first we build the two triangles at the bottom
238     g2.setColor(gp.getInnerColor());
239     for (int i=0; i<2; i++) {
240       xOffset = leftMargin+i*(axisLength[X]+piperSep)/2.0;
241       Polygon p = new Polygon();
242       p.addPoint((int)(xOffset+triangleBottom/4.0),
243      (int)(topMargin+axisLength[Y]-triangleHeight/2.0));
244       p.addPoint((int)(xOffset+3.0*triangleBottom/4.0),
245      (int)(topMargin+axisLength[Y]-triangleHeight/2.0));
246       p.addPoint((int)(xOffset+triangleBottom/2.0),
247      (int)(topMargin+axisLength[Y]));
248       g2.fill(p);
249     }
250     // next, the triangles in the upper one
251     xOffset = leftMargin+(axisLength[X]-triangleBottom/2.0)/2.0;
252     Polygon p = new Polygon();
253     p.addPoint((int)(xOffset),
254          (int)(topMargin+axisLength[Y]-triangleHeight/2.0-normalSep));
255     p.addPoint((int)(xOffset+triangleBottom/2.0),
256          (int)(topMargin+axisLength[Y]-triangleHeight/2.0-normalSep));
257     p.addPoint((int)(xOffset),
258          (int)(topMargin+triangleHeight/2.0));
259     p.addPoint((int)(xOffset+triangleBottom/2.0),
260          (int)(topMargin+triangleHeight/2.0));
261     g2.fill(p);
262   }
263 
264   protected boolean setMinMax(int axis, Vector data) {
265     return true;
266   }  
267 
268   /*
269    * This function draws the axes (actually X,Y and mirror axes) and 
270    * the tics on the axes.
271    * @param g2 instance of a graphical canvas on which to draw the axes
272    * @param background true if this function should draw only the
273    * background color of the axis system.
274    */
275   private void plotAxes(Graphics2D g2, boolean background) {
276     // draw the bounding box:
277     double x = leftMargin;
278     double y = axisLength[Y] + topMargin;
279     
280     // draw triangles:
281     for (int i=0; i<2; i++) {
282       Polygon p = new Polygon();
283       int x1 = (int)(x + (triangleBottom + piperSep)*i);
284       p.addPoint(x1,(int)y);
285       p.addPoint(x1 + (int)triangleBottom,(int)y);
286       p.addPoint(x1 + (int)triangleBottom/2,(int)(y-triangleHeight));
287       if (background) {
288   g2.setColor(gp.getGraphBackgroundColor());
289   g2.fill(p);
290       }
291       else {
292   g2.setColor(gp.getAxesColor());
293   g2.draw(p);
294       }
295     }
296     Polygon p = new Polygon();
297     p.addPoint((int)(x+triangleBottom+piperSep/2),(int)(y-normalSep));
298     p.addPoint((int)(x+(triangleBottom+piperSep)/2),
299          (int)(y-triangleHeight-normalSep));
300     p.addPoint((int)(x+triangleBottom+piperSep/2),
301          (int)(topMargin));
302     p.addPoint((int)(x+(3*triangleBottom+piperSep)/2),
303          (int)(y-triangleHeight-normalSep));
304     if (background) {
305       g2.setColor(gp.getGraphBackgroundColor());
306       g2.fill(p);
307     }
308     else {
309       g2.setColor(gp.getAxesColor());
310       g2.draw(p);
311       drawTics(g2);
312     }
313   }
314 
315   /*
316    * Draw the labels around the x- and y-tics. The xLabelHeight is determined
317    * as a function of one label-height (assuming the height is the same for
318    * all the labels).
319    * @param g2 instance of a 2D graphical canvas
320    */
321   private void plotTicLabels(Graphics2D g2) {
322     float x, y;
323     double a = topMargin + axisLength[Y];
324     double f;
325     
326     // draw the X-axis labels:
327     double xOffset = leftMargin;
328     int k;
329     if (gp.drawTicLabels(X)) {
330       FontMetrics fm = getFontMetrics(gp.getTicFont(X));
331       double xLabelHeight = fm.getHeight();
332       g2.setColor(gp.getTicColor(X));
333       g2.setFont(gp.getTicFont(X));
334       for (int j=0; j<2; j++) {
335   if (j>0) xOffset += triangleBottom + piperSep;
336   for (int i=0; i<numberOfTics[X]; i++) {
337     if (j > 0) k = i;
338     else k = numberOfTics[X]-1 - i;
339     x = (float)(xOffset+sep[X]*i-fm.stringWidth(ticLabel[X][k])/2);
340     y = (float)(a+xLabelHeight);
341     g2.drawString(ticLabel[X][k],x,y);
342   }
343       }
344     }
345     
346     // draw the Y axes labels:
347     if (gp.drawTicLabels(Y)) {
348       FontMetrics fm = getFontMetrics(gp.getTicFont(Y));
349       double yLabelHeight = fm.getHeight();
350       g2.setColor(gp.getTicColor(Y));
351       g2.setFont(gp.getTicFont(Y));
352       for (k=0; k<2; k++) {
353   double yOffset=k*(triangleHeight + normalSep);
354   xOffset = leftMargin + k*(triangleBottom+piperSep)/2.0;
355   double sign=1.0;
356   for (int j=0; j<2; j++) {
357     if (j == 1) {
358       sign = -1.0;
359       xOffset = leftMargin + axisLength[X] + 
360         k*sign*(triangleBottom+piperSep)/2.0;
361     }
362     for (int i=0; i<numberOfTics[Y]; i++) {
363       x = (float)(xOffset+(j-1)*
364       fm.stringWidth(ticLabel[Y][i])-sign*xSep);
365       x += sign*sep[X]*i/2;
366       y = (float)(a-sep[Y]*i+yLabelHeight/4 - yOffset);
367       g2.drawString(ticLabel[Y][i],x,y);
368     }
369   }
370       }
371     }
372   }
373 
374   // dummy instance
375   protected double toX(double x) {
376     return x;
377   }
378   
379   /**
380    * Returns the X-value scaled to the pixel-availability.
381    * This function takes the X-value and returns the corresponding
382    * coordinates for the panel.
383    * @param x real x-value (as introduced by the data)
384    * @param y y-value in pixels
385    * @return x-value scaled to the actual panel coordinates
386    */
387   protected double toX(double x, double y) {
388     return leftMargin-triangleHeight*(y/gp.getMaxValue(Y))/tan +
389       (gp.getMaxValue(X)-x)*triangleBottom/gp.getMaxValue(X);
390   }
391 
392   /**
393    * Returns the X-value scaled to the pixel-availability.
394    * This function takes the X-value and returns the corresponding
395    * coordinates for the panel.
396    * @param x real x-value (as introduced by the data)
397    * @param y y-value in pixels
398    * @return x-value scaled to the actual panel coordinates
399    */
400   protected double toX2(double x, double y) {
401     return leftMargin + axisLength[X] -
402       triangleBottom + triangleHeight*(y/gp.getMaxValue(Y))/tan +
403       x*triangleBottom/gp.getMaxValue(X);
404   }
405 
406   /**
407    * Returns the X-value scaled to the pixel-availability.
408    * This function takes the X-value and returns the corresponding
409    * coordinates the upper triangles.
410    * @param x real x-value (as introduced by the data)
411    * @param y y-value in pixels
412    * @return x-value scaled to the actual panel coordinates
413    */
414   protected double toX3(double x, double y) {
415     return leftMargin + axisLength[X]/2.0 + 
416       cos*(y-x)*triangleSide/gp.getMaxValue(X);
417   }
418 
419   /**
420    * Returns the Y-value scaled to the pixel-availability.
421    * This function takes the Y-value and returns the corresponding
422    * coordinates for the lower triangles.
423    * @param y real y-value (as introduced by the data)
424    * @return y-value scaled to the actual panel coordinates
425    */
426   protected double toY(double y) {
427     return topMargin + axisLength[Y] - triangleHeight*(y/gp.getMaxValue(Y));
428   }
429 
430   /**
431    * Returns the Y-value scaled to the pixel-availability.
432    * This function takes the Y-value and returns the corresponding
433    * coordinates for the upper part of the graph.
434    * @param y real y-value (as introduced by the data)
435    * @return y-value scaled to the actual panel coordinates
436    */
437   protected double toY3(double x, double y) {
438     return topMargin + axisLength[Y] - normalSep -
439       sin*(x+y)*triangleSide/gp.getMaxValue(Y);
440   }
441 
442   /**
443    * Fills the graph area with a background color. The
444    * area is the area between the axes.
445    * @param g2 graphics canvas
446    */
447   protected void fillGraphArea(Graphics2D g2) {
448     plotAxes(g2,true);
449   }
450 
451   /**
452    * This function builds the graph in a double-buffered image zone.
453    */
454   protected void updateGraph() {
455     Graphics2D g2  = createGraphics();
456     double x, y;
457     double a = topMargin + axisLength[Y];
458 
459     // draw the on the background, if this is what they want:
460     if (gp.showInner()) drawFilledTriangles(g2);
461     g2.setStroke(new BasicStroke());
462     if (!gp.gridToFront()) drawGrid(g2);
463 
464     int i;
465     for (Enumeration e=data.elements(); e.hasMoreElements();) {
466       
467       // get the next data array from the vector:
468       DataArray da = (DataArray)e.nextElement();
469 
470       // set color and penwidth:
471       g2.setColor(da.getColor());
472       g2.setStroke(da.getStroke());
473       x = toX(da.getX(0),da.getY(0));
474       y = toY(da.getY(0));
475       drawPointType(da.getSymbol(),g2,x,y,da.getSymbolSize());
476       x = toX2(da.getX(1),da.getY(1));
477       y = toY(da.getY(1));
478       drawPointType(da.getSymbol(),g2,x,y,da.getSymbolSize());
479       x = toX3(da.getX(0)+da.getY(0),da.getX(1)+da.getY(1));
480       y = toY3(da.getX(0)+da.getY(0),da.getX(1)+da.getY(1));
481       drawPointType(da.getSymbol(),g2,x,y,da.getSymbolSize());
482       if (gp.drawTds() && da.size() > 2) {
483   g2.setStroke(new BasicStroke());
484   drawPointType(0,g2,x,y,(float)(gp.getTdsFactor()*
485                da.getSymbolSize()*da.getX(2)));
486       }
487     }
488     g2.setStroke(new BasicStroke());
489 
490     // draw the on the foreground, if this is what they want:
491     if (gp.gridToFront()) drawGrid(g2);
492 
493     // draw the axes and tics:
494     plotAxes(g2,false);
495     
496     // draw the tic labels:
497     plotTicLabels(g2);
498     
499     // plot the labels:
500     plotLabels(g2);
501 
502     // draw the legend. Do this at the end because it must be
503     // drawn on the top of all other drawing stuff (e.g. grid...)
504     if (gp.drawLegend()) {
505       int k=0;
506       g2.setFont(gp.getLegendFont());
507       for (Enumeration e=data.elements(); e.hasMoreElements(); k++) {
508   DataArray da = (DataArray)e.nextElement();
509   if (!da.drawLegend()) k--;
510   else {
511     g2.setColor(da.getColor());
512     if (da.drawLine()) g2.setStroke(da.getStroke());
513     drawLegend(g2,da,k);
514   }
515       }
516     }
517     g2.setStroke(new BasicStroke());
518     repaint();
519   }
520 
521   /**
522    * Checks whether x and y are within the ranges. The ranges are
523    * defined by the axes system.
524    * @param x x-point
525    * @param y y-point
526    */
527   private boolean inRange(double x, double y) {
528     if (x < leftMargin || x > leftMargin + axisLength[X] ||
529   y < topMargin || y > topMargin + axisLength[Y]) return false;
530     return true;
531   }
532 }