source: src/main/java/agents/anac/y2015/agentBuyogV2/flanagan/plot/Plot.java

Last change on this file was 127, checked in by Wouter Pasman, 6 years ago

#41 ROLL BACK of rev.126 . So this version is equal to rev. 125

File size: 60.8 KB
Line 
1/*
2* Class Plot
3*
4* Superclass for the plotting subclasses:
5* PlotGraph and PlotPoleZero
6*
7* WRITTEN BY: Dr Michael Thomas Flanagan
8*
9* DATE: February 2002
10* REVISED: 20 July 2005, 7 July 2008, 27 July 2008, 11 August 2008
11*
12* Copyright (c) 2002 - 2008
13*
14* DOCUMENTATION
15* http://www.ee.ucl.ac.uk/~mflanaga/java/PlotGraph.html
16* http://www.ee.ucl.ac.uk/~mflanaga/java/
17*
18* PERMISSION TO COPY:
19* Permission to use, copy and modify this software and its documentation for
20* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement
21* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies.
22*
23* Dr Michael Thomas Flanagan makes no representations about the suitability
24* or fitness of the software for any or for a particular purpose.
25* Michael Thomas Flanagan shall not be liable for any damages suffered
26* as a result of using, modifying or distributing this software or its derivatives.
27*
28***************************************************************************************/
29
30
31package agents.anac.y2015.agentBuyogV2.flanagan.plot;
32
33import java.awt.*;
34import java.io.Serializable;
35
36import agents.anac.y2015.agentBuyogV2.flanagan.interpolation.CubicSpline;
37import agents.anac.y2015.agentBuyogV2.flanagan.math.ArrayMaths;
38import agents.anac.y2015.agentBuyogV2.flanagan.math.Fmath;
39
40public class Plot extends Canvas implements Serializable{
41
42 protected static final long serialVersionUID = 1L; // serial version unique identifier
43
44 protected double[][] data = null; // data to be plotted
45 // data[i][] i = 0, 2, 4 . . . x values
46 // data[i][] i = 1, 3, 5 . . . y values for x[i-1][]
47 protected double[][] copy = null; // copy of original data to be plotted
48 protected int nCurves = 0; // number of curves
49 protected int[] nPoints = null; // number of points points on curve each curve
50 protected int nmPoints = 0; // number of points points on curve with most points
51 protected int niPoints = 200; // number of cubic spline interpolation points
52 protected int[] pointOpt = null; // point plotting option for each curve
53 // pointOpt = 0: no points plotted
54 // pointOpt = i where i = 1,2,3,4,5,6,7,8: points plotted
55 // default options
56 // curve 1 - open circles
57 // curve 2 - open squares
58 // curve 3 - open diamonds
59 // curve 4 - filled circles
60 // curve 5 - filled squares
61 // curve 6 - filled diamonds
62 // curve 7 - x crosses
63 // curve 8 - + crosses
64 // further curves - above sequence repeated
65 protected int[] pointSize = null; // point size in pixels for each curve
66 protected int npTypes = 8; // number of point types
67 protected boolean[] errorBar = null; // true - error bar plotted, flase no error bar plotted - default = false
68 protected double[][] errors = null; // error bar values - should be an estimate of the sd of the variable
69 protected double[][] errorsCopy = null; // copy of error bar values
70 protected int[] lineOpt = null; // line drawing option for each curve
71 // lineOpt = 0: no line plotted
72 // lineOpt = 1: cubic spline interpolation line plotted as a continuous line
73 // lineOpt = 2: cubic spline interpolation line plotted as a dashed line
74 // lineOpt = 3: line plotted by joining points
75 // lineOpt = 4: dashed line plotted by joining points
76 // default - lineOpt = 1
77 protected int[] dashLength = null; // dash length in lineOpt = 2
78 protected boolean[] minMaxOpt = null;// true - curve included in maximum and minimum axes value calculation
79 protected boolean[] trimOpt = null; // true - curve trimmed to fit axes rectangle
80
81 protected int fontSize = 14; // text font size
82 protected int xLen = 625; // length of the x axis in pixels
83 protected int yLen = 375; // length of the y axis in pixels
84 protected int xBot = 100; // x coordinate of the bottom of the x axis in pixels
85 protected int xTop = xBot+xLen; // x coordinate of the top of the x axis in pixels
86 protected int yTop = 110; // y coordinate of the top of the y axis in pixels
87 protected int yBot = yTop+yLen; // y coordinate of the bottom of the y axis in pixels
88
89 protected double xLow = 0; // scaled lower limit data value of the x axis
90 protected double xHigh = 0; // scaled upper limit data value of the x axis
91 protected double yLow = 0; // scaled lower limit data value of the y axis
92 protected double yHigh = 0; // scaled upper limit data value of the y axis
93 protected int xFac = 0; // decadic exponent of x axis scaling factor
94 protected int yFac = 0; // decadic exponent of y axis scaling factor
95 protected int xTicks = 0; // number of x axis ticks
96 protected int yTicks = 0; // number of y axis ticks
97
98 protected double xMin = 0.0D; // minimum x data value
99 protected double xMax = 0.0D; // maximum x data value
100 protected double yMin = 0.0D; // minimum y data value
101 protected double yMax = 0.0D; // maximum y data value
102
103 protected double xOffset = 0.0D; // xaxis data value offset
104 protected double yOffset = 0.0D; // y axis data value offset
105 protected boolean noXoffset = false; // no x axis offset allowed if true
106 protected boolean noYoffset = false; // no y axis offset allowed if true
107 protected double xLowFac = 0.75D; // x axis data setting low factor
108 protected double yLowFac = 0.75D; // y axis data setting low factor
109
110 protected String graphTitle = " "; // graph title
111 protected String graphTitle2 = " "; // graph title (secondline)
112 protected String xAxisLegend = " "; // x axis legend title
113 protected String xAxisUnits = " "; // x axis unit name, e.g. V, ohm
114 protected String yAxisLegend = " "; // y axis legend title
115 protected String yAxisUnits = " "; // x axis unit name
116
117 protected boolean xZero = false; // if true - a (x=0) zero line is required
118 protected boolean yZero = false; // if true - a (y=0) zero line required
119 protected boolean noXunits = true; // if true - no x axis units
120 protected boolean noYunits = true; // if true - no y axis units
121
122 protected double[] xAxisNo = new double[50]; // x axis legend numbers as double
123 protected double[] yAxisNo = new double[50]; // y axis legend numbers as double
124 protected String[] xAxisChar = new String[50]; // x axis legend numbers as char
125 protected String[] yAxisChar = new String[50]; // y axis legend numbers as char
126 protected int[] axisTicks = new int[50]; // no of ticks for scaled lengths
127
128 protected static double dataFill = 3.0e200; // value used to initialise data array by Plot.data()
129
130
131 // Constructor
132 //One 2-dimensional data arrays
133 public Plot(double[][] data){
134 this.initialise(data);
135 }
136
137 // Constructor
138 //Two 1-dimensional data arrays
139 public Plot(double[] xdata, double[] ydata){
140 int xl = xdata.length;
141 int yl = ydata.length;
142 if(xl!=yl)throw new IllegalArgumentException("x-data length is not equal to the y-data length");
143 double[][] data = new double[2][xl];
144 for(int i=0; i<xl; i++){
145 data[0][i] = xdata[i];
146 data[1][i] = ydata[i];
147 }
148 this.initialise(data);
149 }
150
151 // Initialisation
152 private void initialise(double[][] cdata){
153
154 // Calculate number of curves
155 this.nCurves = cdata.length/2;
156
157 // Initialize 1D class arrays
158 this.nPoints = new int[nCurves];
159 this.lineOpt = new int[nCurves];
160 this.dashLength = new int[nCurves];
161 this.trimOpt = new boolean[nCurves];
162 this.minMaxOpt = new boolean[nCurves];
163 this.pointOpt = new int[nCurves];
164 this.pointSize = new int[nCurves];
165 this.errorBar = new boolean[nCurves];
166
167 // Calculate maximum number of points on a single curve
168 this.nmPoints = 0;
169 int ll = 0;
170 for(int i=0; i<2*nCurves; i++){
171 if((ll=cdata[i].length)>nmPoints)nmPoints=ll;
172 }
173
174 // Initialize class 2D arrays
175 this.data = new double[2*nCurves][nmPoints];
176 this.copy = new double[2*nCurves][nmPoints];
177 this.errors = new double[nCurves][nmPoints];
178 this.errorsCopy = new double[nCurves][nmPoints];
179
180
181 // Calculate curve lengths
182 // and check all individual curves have an equal number of abscissae and ordinates
183 int k = 0, l1 = 0, l2 = 0;
184 boolean testlen=true;
185 for(int i=0; i<nCurves; i++){
186 k=2*i;
187 testlen=true;
188 l1=cdata[k].length;
189 l2=cdata[k+1].length;
190 if(l1!=l2)throw new IllegalArgumentException("an x and y array length differ");
191 nPoints[i]=l1;
192
193 }
194
195 // Remove both abscissae and ordinates for points equal to dataFill
196 k=0;
197 boolean testopt=true;
198 for(int i=0; i<nCurves; i++){
199 testlen=true;
200 l1=nPoints[i];
201 while(testlen){
202 if(l1<0)throw new IllegalArgumentException("curve array index "+k+ ": blank array");
203 if(cdata[k][l1-1]==dataFill){
204 if(cdata[k+1][l1-1]==dataFill){
205 l1--;
206 testopt=false;
207 }
208 else{
209 testlen=false;
210 }
211 }
212 else{
213 testlen=false;
214 }
215 }
216 nPoints[i]=l1;
217 k+=2;
218 }
219
220 // Sort arrays into ascending order
221 k = 0;
222 for(int i=0; i<nCurves; i++){
223 double[][] xxx = new double[2][nPoints[i]];
224 for(int j=0; j<nPoints[i]; j++){
225 xxx[0][j] = cdata[k][j];
226 xxx[1][j] = cdata[k+1][j];
227 }
228 xxx = doubleSelectionSort(xxx);
229 for(int j=0; j<nPoints[i]; j++){
230 cdata[k][j] = xxx[0][j];
231 cdata[k+1][j] = xxx[1][j];
232 }
233 k += 2;
234 }
235
236 // initialize class data variables
237 k=0;
238 int kk=1;
239 for(int i=0; i<nCurves; i++){
240
241 // reverse order if all abscissae are in descending order
242 int rev = 1;
243 for(int j=1; j<nPoints[i]; j++){
244 if(cdata[k][j]<cdata[k][j-1])rev++;
245 }
246 if(rev==nPoints[i]){
247 double[] hold = new double[nPoints[i]];
248 for(int j=0; j<nPoints[i]; j++)hold[j] = cdata[k][j];
249 for(int j=0; j<nPoints[i]; j++)cdata[k][j] = hold[nPoints[i]-j-1];
250 for(int j=0; j<nPoints[i]; j++)hold[j] = cdata[k+1][j];
251 for(int j=0; j<nPoints[i]; j++)cdata[k+1][j] = hold[nPoints[i]-j-1];
252 }
253
254 // copy arrays
255 for(int j=0; j<nPoints[i]; j++){
256 this.data[k][j]=cdata[k][j];
257 this.data[k+1][j]=cdata[k+1][j];
258 this.copy[k][j]=cdata[k][j];
259 this.copy[k+1][j]=cdata[k+1][j];
260 }
261
262 this.lineOpt[i] = 1;
263 this.dashLength[i] = 5;
264 this.trimOpt[i] = false;
265 if(this.lineOpt[i]==1)trimOpt[i] = true;
266 this.minMaxOpt[i]=true;
267 this.pointSize[i]= 6;
268 this.errorBar[i]= false;
269 this.pointOpt[i] = kk;
270 k+=2;
271 kk++;
272 if(kk>npTypes)kk = 1;
273 }
274 }
275
276 // sort x elements into ascending order with matching switches of y elements
277 // using selection sort method
278 public static double[][] doubleSelectionSort(double[][] aa){
279 int index = 0;
280 int lastIndex = -1;
281 int n = aa[0].length;
282 double holdx = 0.0D;
283 double holdy = 0.0D;
284 double[][] bb = new double[2][n];
285 for(int i=0; i<n; i++){
286 bb[0][i]=aa[0][i];
287 bb[1][i]=aa[1][i];
288 }
289
290
291 while(lastIndex != n-1){
292 index = lastIndex+1;
293 for(int i=lastIndex+2; i<n; i++){
294 if(bb[0][i]<bb[0][index]){
295 index=i;
296 }
297 }
298 lastIndex++;
299 holdx=bb[0][index];
300 bb[0][index]=bb[0][lastIndex];
301 bb[0][lastIndex]=holdx;
302 holdy=bb[1][index];
303 bb[1][index]=bb[1][lastIndex];
304 bb[1][lastIndex]=holdy;
305
306 }
307 return bb;
308 }
309
310
311 //Create a data array initialised to dataFill;
312 public static double[][] data(int n, int m){
313 double[][] d = new double[2*n][m];
314 for(int i=0; i<2*n; i++){
315 for(int j=0; j<m; j++){
316 d[i][j]=dataFill;
317 }
318 }
319 return d;
320 }
321
322 //Change the value used to initialise the datarray
323 public static void setDataFillValue(double dataFill){
324 Plot.dataFill=dataFill;
325 }
326
327 //Get the value used to initialise the datarray
328 public static double getDataFillValue(){
329 return Plot.dataFill;
330 }
331
332 // Enter primary graph title
333 public void setGraphTitle(String graphTitle){
334 this.graphTitle=graphTitle;
335 }
336
337 // Enter second line to graph title
338 public void setGraphTitle2(String graphTitle2){
339 this.graphTitle2=graphTitle2;
340 }
341
342 // Enter x axis legend
343 public void setXaxisLegend(String xAxisLegend){
344 this.xAxisLegend=xAxisLegend;
345 }
346
347 // Enter y axis legend
348 public void setYaxisLegend(String yAxisLegend){
349 this.yAxisLegend=yAxisLegend;
350 }
351
352 // Enter x axis unit name
353 public void setXaxisUnitsName(String xAxisUnits){
354 this.xAxisUnits=xAxisUnits;
355 this.noXunits=false;
356 }
357
358 // Enter y axis unit name
359 public void setYaxisUnitsName(String yAxisUnits){
360 this.yAxisUnits=yAxisUnits;
361 this.noYunits=false;
362 }
363
364 // Get pixel length of the x axis
365 public int getXaxisLen(){
366 return this.xLen;
367 }
368
369 // Get pixel length of the y axis
370 public int getYaxisLen(){
371 return this.yLen;
372 }
373
374 // Get pixel start of the x axis
375 public int getXlow(){
376 return this.xBot;
377 }
378
379 // Get pixel end of the y axis
380 public int getYhigh(){
381 return this.yTop;
382 }
383
384 // Get point size in pixels
385 public int[] getPointsize(){
386 return this.pointSize;
387 }
388
389 // Get dash length in pixels
390 public int[] getDashlength(){
391 return this.dashLength;
392 }
393
394 // Get the x axis low factor
395 public double getXlowFac(){
396 return 1.0D-this.xLowFac;
397 }
398
399 // Get the y axis low factor
400 public double getYlowFac(){
401 return 1.0D-this.yLowFac;
402 }
403
404 // Get the x axis minimum value
405 public double getXmin(){
406 return this.xMin;
407 }
408
409 // Get the x axis maximum value
410 public double getXmax(){
411 return this.xMax;
412 }
413
414 // Get the y axis minimum value
415 public double getYmin(){
416 return this.yMin;
417 }
418
419 // Get the y axis maximum value
420 public double getYmax(){
421 return this.yMax;
422 }
423
424 // get line plotting option
425 public int[] getLine(){
426 return this.lineOpt;
427 }
428
429 // Get point plotting options
430 public int[] getPoint(){
431 return this.pointOpt;
432 }
433
434 // Get the number of points to be used in the cubic spline interpolation
435 public int getNiPoints(){
436 return this.niPoints;
437 }
438
439 // Get font size
440 public int getFontSize(){
441 return this.fontSize;
442 }
443
444 // Reset pixel length of the x axis
445 public void setXaxisLen(int xLen){
446 this.xLen=xLen;
447 this.update();
448 }
449
450 // Reset pixel length of the y axis
451 public void setYaxisLen(int yLen){
452 this.yLen=yLen;
453 this.update();
454 }
455
456 // Reset pixel start of the x axis
457 public void setXlow(int xBot){
458 this.xBot=xBot;
459 this.update();
460 }
461
462 // Reset pixel end of the y axis
463 public void setYhigh(int yTop){
464 this.yTop=yTop;
465 this.update();
466 }
467
468 // Reset the x axis low factor
469 public void setXlowFac(double xLowFac){
470 this.xLowFac=1.0D-xLowFac;
471 }
472
473 // Reset the y axis low factor
474 public void setYlowFac(double yLowFac){
475 this.yLowFac=1.0D-yLowFac;
476 }
477
478 // Reset the x axis offset option
479 public void setNoXoffset(boolean noXoffset){
480 this.noXoffset=noXoffset;
481 }
482
483 // Reset the y axis offset option
484 public void setNoYoffset(boolean noYoffset){
485 this.noYoffset=noYoffset;
486 }
487
488 // Reset both the x and y axis offset options to the same optio
489 public void setNoOffset(boolean nooffset){
490 this.noXoffset=nooffset;
491 this.noYoffset=nooffset;
492 }
493
494 // Get the x axis offset option
495 public boolean getNoXoffset(){
496 return this.noXoffset;
497 }
498
499 // RGet the y axis offset option
500 public boolean getNoYoffset(){
501 return this.noYoffset;
502 }
503
504 // Update axis pixel position parameters
505 protected void update(){
506 this.xTop = this.xBot + this.xLen;
507 this.yBot = this.yTop + this.yLen;
508 }
509
510 // Overwrite line plotting option with different options for individual curves
511 public void setLine(int[] lineOpt){
512 int n=lineOpt.length;
513 if(n!=nCurves)throw new IllegalArgumentException("input array of wrong length");
514 for(int i=0; i<n; i++)if(lineOpt[i]<0 || lineOpt[i]>4)throw new IllegalArgumentException("lineOpt must be 0, 1, 2, 3 or 4");
515 this.lineOpt=lineOpt;
516
517 // check if data supports cubic spline interpolation if lineOpt = 1 or 2
518 for(int i=0; i<this.lineOpt.length; i++){
519 if(this.lineOpt[i]==1 || this.lineOpt[i]==2){
520 // check if some points reverse direction
521 boolean test0 = false;
522 for(int j=1; j<this.nPoints[i]; j++){
523 if(data[i][j]<data[i][j-1])test0=true;
524 }
525 if(test0){
526 // check if y all in ascending order
527 int rev = 1;
528 for(int j=1; j<nPoints[i]; j++){
529 if(data[2*i][j]>data[2*i][j-1])rev++;
530 }
531 if(rev==nPoints[i]){
532 lineOpt[i]=-lineOpt[i];
533 }
534 else{
535 // check if y all in descending order
536 rev = 1;
537 for(int j=1; j<nPoints[i]; j++){
538 if(data[2*i][j]<data[2*i][j-1])rev++;
539 }
540 if(rev==nPoints[i]){
541 // reverse order of y
542 double[] hold = new double[nPoints[i]];
543 for(int j=0; j<nPoints[i]; j++)hold[j] = data[i][j];
544 for(int j=0; j<nPoints[i]; j++)data[i][j] = hold[nPoints[i]-j-1];
545 for(int j=0; j<nPoints[i]; j++)hold[j] = data[2*i][j];
546 for(int j=0; j<nPoints[i]; j++)data[2*i][j] = hold[nPoints[i]-j-1];
547 this.lineOpt[i] = - lineOpt[i];
548 }
549 else{
550 System.out.println("Curve "+i+" will not support interpolation");
551 System.out.println("Straight connecting line option used");
552 if(this.lineOpt[i]==1) this.lineOpt[i] = 3;
553 if(this.lineOpt[i]==2) this.lineOpt[i] = 4;
554 }
555 }
556 }
557 }
558 }
559 }
560
561 // Overwrite line plotting option with a single option for all curves
562 public void setLine(int slineOpt){
563 if(slineOpt<0 || slineOpt>3)throw new IllegalArgumentException("lineOpt must be 0, 1, 2 or 3");
564 for(int i=0; i<this.nCurves; i++)this.lineOpt[i]=slineOpt;
565 }
566
567 // Overwrite dash length with different options for individual curves
568 public void setDashLength(int[] dashLength){
569 if(dashLength.length!=nCurves)throw new IllegalArgumentException("input array of wrong length");
570 this.dashLength=dashLength;
571 }
572
573 // Overwrite dashLength with a single option for all curves
574 public void setDashLength(int sdashLength){
575 for(int i=0; i<this.nCurves; i++)this.dashLength[i]=sdashLength;
576 }
577
578 // Overwrite point plotting option with different options for individual curves
579 public void setPoint(int[] pointOpt){
580 int n=pointOpt.length;
581 if(n!=nCurves)throw new IllegalArgumentException("input array of wrong length");
582 for(int i=0; i<n; i++)if(pointOpt[i]<0 || pointOpt[i]>8)throw new IllegalArgumentException("pointOpt must be 0, 1, 2, 3, 4, 5, 6, 7, or 8");
583 this.pointOpt=pointOpt;
584 }
585
586 // Overwrite point plotting option with a single option for all curves
587 public void setPoint(int spointOpt){
588 if(spointOpt<0 || spointOpt>8)throw new IllegalArgumentException("pointOpt must be 0, 1, 2, 3, 4, 5, 6, 7, or 8");
589 for(int i=0; i<this.nCurves; i++)this.pointOpt[i]=spointOpt;
590 }
591
592 // Overwrite point size with different options for individual curves
593 public void setPointSize(int[] mpointSize){
594 if(mpointSize.length!=nCurves)throw new IllegalArgumentException("input array of wrong length");
595 for(int i=0; i<this.nCurves; i++){
596 if(mpointSize[i]!=(mpointSize[i]/2)*2)mpointSize[i]++;
597 this.pointSize[i]=mpointSize[i];
598 }
599 }
600
601 // Overwrite point size with a single option for all curves
602 public void setPointSize(int spointSize){
603 if(spointSize%2!=0)spointSize++;
604 for(int i=0; i<this.nCurves; i++)this.pointSize[i]=spointSize;
605 }
606
607 // Set errorBar values
608 // Must set each curve individually
609 // nc is the curve identifier (remember curves start at 0)
610 // err are the error bar values which should be an estimate of the standard devition of the experimental point
611 public void setErrorBars(int nc, double[] err){
612 if(err.length!=this.nPoints[nc])throw new IllegalArgumentException("input array of wrong length");
613 this.errorBar[nc] = true;
614 for(int i=0; i<this.nPoints[nc]; i++){
615 this.errors[nc][i] = err[i];
616 this.errorsCopy[nc][i] = err[i];
617 }
618 }
619
620 // overwrite the number of points to be used in the cubic spline interpolation
621 public void setNiPoints(int niPoints){
622 this.niPoints=niPoints;
623 }
624
625 // overwrite the font size
626 public void setFontSize(int fontSize){
627 this.fontSize=fontSize;
628 }
629
630 // overwrite the trim option
631 public void setTrimOpt(boolean[] trim){
632 this.trimOpt=trim;
633 }
634
635 // overwrite the minMaxOpt option
636 public void setMinMaxOpt(boolean[] minmax){
637 this.minMaxOpt=minmax;
638 }
639
640 // Calculate scaling factors
641 public static int scale(double mmin, double mmax){
642 int fac=0;
643 double big=0.0D;
644 boolean test=false;
645
646 if(mmin>=0.0 && mmax>0.0){
647 big=mmax;
648 test=true;
649 }
650 else{
651 if(mmin<0.0 && mmax<=0.0){
652 big=-mmin;
653 test=true;
654 }
655 else{
656 if(mmax>0.0 && mmin<0.0){
657 big=Math.max(mmax, -mmin);
658 test=true;
659 }
660 }
661 }
662
663 if(test){
664 if(big>100.0){
665 while(big>1.0){
666 big/=10.0;
667 fac--;
668 }
669 }
670 if(big<=0.01){
671 while(big<=0.10){
672 big*=10.0;
673 fac++;
674 }
675 }
676 }
677 return fac;
678 }
679
680 // Set low value on axis
681 public static void limits(double low, double high, double lowfac, double[]limits){
682
683 double facl = 1.0D;
684 double fach = 1.0D;
685 if(Math.abs(low)<1.0D)facl=10.0D;
686 if(Math.abs(low)<0.1D)facl=100.0D;
687 if(Math.abs(high)<1.0D)fach=10.0D;
688 if(Math.abs(high)<0.1D)fach=100.0D;
689
690 double ld=Math.floor(10.0*low*facl)/facl;
691 double hd=Math.ceil(10.0*high*fach)/fach;
692
693 if(ld>=0.0D && hd>0.0D){
694 if(ld<lowfac*hd){
695 ld=0.0;
696 }
697 }
698 if(ld<0.0D && hd<=0.0D){
699 if(-hd <= -lowfac*ld){
700 hd=0.0;
701 }
702 }
703 limits[0] = ld/10.0;
704 limits[1] = hd/10.0;
705 }
706
707 // Calculate axis offset value
708 public static double offset(double low, double high){
709
710 double diff = high - low;
711 double sh = Fmath.sign(high);
712 double sl = Fmath.sign(low);
713 double offset=0.0D;
714 int eh=0, ed=0;
715
716 if(sh == sl){
717 ed=(int)Math.floor(Fmath.log10(diff));
718 if(sh==1){
719 eh=(int)Math.floor(Fmath.log10(high));
720 if(eh-ed>1)offset = Math.floor(low*Math.pow(10, -ed))*Math.pow(10,ed);
721 }
722 else{
723 eh=(int)Math.floor(Fmath.log10(Math.abs(low)));
724 if(eh-ed>1)offset = Math.floor(high*Math.pow(10, -ed))*Math.pow(10,ed);
725 }
726 }
727 return offset;
728 }
729
730
731 // Calculate scaling and offset values for both axes
732 public void axesScaleOffset(){
733
734 double[] limit = new double[2];
735
736 // tranfer data from copy to enable redrawing
737 int k=0;
738 for(int i=0; i<nCurves; i++){
739 for(int j=0; j<nPoints[i]; j++){
740 this.data[k][j]=this.copy[k][j];
741 this.data[k+1][j]=this.copy[k+1][j];
742 this.errors[i][j]=this.errorsCopy[i][j];
743 if(this.errorBar[i])this.errors[i][j]+=this.data[k+1][j];
744 }
745 k+=2;
746 }
747
748 // Find mimium and maximum data values
749 minMax();
750
751 // Calculate x axis offset values and subtract it from the data
752 if(!noXoffset)this.xOffset=offset(this.xMin, this.xMax);
753 if(this.xOffset!=0.0){
754 k=0;
755 for(int i=0; i<this.nCurves; i++){
756 for(int j=0; j<this.nPoints[i]; j++){
757 this.data[k][j] -= this.xOffset;
758 }
759 k+=2;
760 }
761 this.xMin -= this.xOffset;
762 this.xMax -= this.xOffset;
763 }
764
765 // Calculate y axis offset values and subtract it from the data
766 if(!noYoffset)this.yOffset=offset(this.yMin, this.yMax);
767 if(this.yOffset!=0.0){
768 k=1;
769 for(int i=0; i<this.nCurves; i++){
770 for(int j=0; j<this.nPoints[i]; j++){
771 this.data[k][j] -= this.yOffset;
772 if(this.errorBar[i])this.errors[i][j] -= this.yOffset;
773 }
774 k+=2;
775 }
776 this.yMin -= this.yOffset;
777 this.yMax -= this.yOffset;
778 }
779
780 // Calculate x axes scale values and scale data
781 this.xFac = scale(this.xMin, this.xMax);
782 if(this.xFac!=0){
783 k=0;
784 for(int i=0; i<this.nCurves; i++){
785 for(int j=0; j<this.nPoints[i]; j++){
786 this.data[k][j] *= Math.pow(10, this.xFac+1);
787 }
788 k+=2;
789 }
790 this.xMin *= Math.pow(10, this.xFac+1);
791 this.xMax *= Math.pow(10, this.xFac+1);
792 }
793
794 // Calculate y axes scale values and scale data
795 this.yFac = scale(this.yMin, this.yMax);
796 if(this.yFac!=0){
797 k=1;
798 for(int i=0; i<this.nCurves; i++){
799 for(int j=0; j<this.nPoints[i]; j++){
800 this.data[k][j] *= Math.pow(10, yFac+1);
801 if(this.errorBar[i])this.errors[i][j] *= Math.pow(10, this.yFac+1);
802 }
803 k+=2;
804 }
805 this.yMin *= Math.pow(10, this.yFac+1);
806 this.yMax *= Math.pow(10, this.yFac+1);
807 }
808
809 // Calculate scaled low and high values
810 // x axis
811 limits(this.xMin, this.xMax, this.xLowFac, limit);
812 this.xLow = limit[0];
813 this.xHigh = limit[1];
814 if(xLow<0 && xHigh>0)xZero=true;
815 // y axis
816 limits(this.yMin, this.yMax, this.yLowFac, limit);
817 this.yLow = limit[0];
818 this.yHigh = limit[1];
819 if(yLow<0 && yHigh>0)yZero=true;
820
821 // Calculate tick parameters
822 // x axis
823 this.xTicks = ticks(this.xLow, this.xHigh, this.xAxisNo, this.xAxisChar);
824 this.xHigh = this.xAxisNo[this.xTicks-1];
825 if(this.xLow!=this.xAxisNo[0]){
826 if(this.xOffset!=0.0D){
827 this.xOffset = this.xOffset - this.xLow + this.xAxisNo[0];
828 }
829 this.xLow = this.xAxisNo[0];
830 }
831 // y axis
832 this.yTicks = ticks(this.yLow, this.yHigh, this.yAxisNo, this.yAxisChar);
833 this.yHigh = this.yAxisNo[this.yTicks-1];
834 if(this.yLow!=this.yAxisNo[0]){
835 if(this.yOffset!=0.0D){
836 this.yOffset = this.yOffset - this.yLow + this.yAxisNo[0];
837 }
838 this.yLow = this.yAxisNo[0];
839 }
840
841 }
842
843 // Calculate axis ticks and tick values
844 public static int ticks(double low, double high, double[] tickval, String[] tickchar){
845
846
847 // Find range
848 int[] trunc = {1, 1, 1, 2, 3};
849 double[] scfac1 = {1.0, 10.0, 1.0, 0.1, 0.01};
850 double[] scfac2 = {1.0, 1.0, 0.1, 0.01, 0.001};
851
852 double rmax = Math.abs(high);
853 double temp = Math.abs(low);
854 if(temp>rmax)rmax = temp;
855 int range = 0;
856 if(rmax<=100.0D){
857 range = 1;
858 }
859 if(rmax<=10.0D){
860 range = 2;
861 }
862 if(rmax<=1.0D){
863 range = 3;
864 }
865 if(rmax<=0.1D){
866 range = 4;
867 }
868 if(rmax>100.0D || rmax<0.01)range = 0;
869
870 // Calculate number of ticks
871 double inc = 0.0D;
872 double bot = 0.0D;
873 double top = 0.0D;
874 int sgn = 0;
875 int dirn = 0;
876 if(high>0.0D && low>=0.0D){
877 inc = Math.ceil((high-low)/scfac1[range])*scfac2[range];
878 dirn = 1;
879 bot = low;
880 top = high;
881 sgn = 1;
882 }
883 else{
884 if(high<=0 && low<0.0D){
885 inc = Math.ceil((high-low)/scfac1[range])*scfac2[range];
886 dirn = -1;
887 bot = high;
888 top = low;
889 sgn = -1;
890 }
891 else{
892 double up = Math.abs(Math.ceil(high));
893 double down = Math.abs(Math.floor(low));
894 int np = 0;
895 if(up>=down){
896 dirn = 2;
897 np = (int)Math.rint(10.0*up/(up+down));
898 inc = Math.ceil((high*10/np)/scfac1[range])*scfac2[range];
899 bot = 0.0D;
900 top = high;
901 sgn = 1;
902 }
903 else{
904 dirn = -2;
905 np = (int)Math.rint(10.0D*down/(up+down));
906 inc = Math.ceil((Math.abs(low*10/np))/scfac1[range])*scfac2[range];
907 bot = 0.0D;
908 top = low;
909 sgn = -1;
910 }
911 }
912 }
913
914 int nticks = 1;
915 double sum = bot;
916 boolean test = true;
917 while(test){
918 sum = sum + sgn*inc;
919 nticks++;
920 if(Math.abs(sum)>=Math.abs(top))test=false;
921 }
922
923 // Calculate tick values
924 int npExtra = 0;
925 double[] ttickval = null;;
926 switch(dirn){
927 case 1: ttickval = new double[nticks];
928 tickval[0]=Fmath.truncate(low, trunc[range]);
929 for(int i=1; i<nticks; i++){
930 tickval[i] = Fmath.truncate(tickval[i-1]+inc, trunc[range]);
931 }
932 break;
933 case -1: ttickval = new double[nticks];
934 ttickval[0]=Fmath.truncate(high, trunc[range]);
935 for(int i=1; i<nticks; i++){
936 ttickval[i] = Fmath.truncate(ttickval[i-1]-inc, trunc[range]);
937 }
938 ttickval = Fmath.reverseArray(ttickval);
939 for(int i=0; i<nticks; i++)tickval[i] = ttickval[i];
940 break;
941 case 2: npExtra = (int)Math.ceil(-low/inc);
942 nticks += npExtra;
943 ttickval = new double[nticks];
944 tickval[0]=Fmath.truncate(-npExtra*inc, trunc[range]);
945 for(int i=1; i<nticks; i++){
946 tickval[i] = Fmath.truncate(tickval[i-1]+inc, trunc[range]);
947 }
948 break;
949 case -2: npExtra = (int)Math.ceil(high/inc);
950 nticks += npExtra;
951 ttickval = new double[nticks];
952 ttickval[0]=Fmath.truncate(npExtra*inc, trunc[range]);
953 for(int i=1; i<nticks; i++){
954 ttickval[i] = Fmath.truncate(ttickval[i-1]-inc, trunc[range]);
955 }
956 ttickval = Fmath.reverseArray(ttickval);
957 for(int i=0; i<nticks; i++)tickval[i] = ttickval[i];
958 break;
959 }
960
961 // ensure a zero value is truly zero and not a zero with rounding errors, e.g. 1e-17
962 ArrayMaths am = new ArrayMaths(tickval);
963 double max = am.maximum();
964 double min = Math.abs(am.minimum());
965 boolean testZero = true;
966 int counter = 0;
967 while(testZero){
968 if(Math.abs(tickval[counter])<max*1e-4 || Math.abs(tickval[counter])<min*1e-4){
969 tickval[counter] = 0.0;
970 testZero = false;
971 }
972 else{
973 counter++;
974 if(counter>=nticks)testZero = false;
975 }
976 }
977
978 // set String form of tick values
979 for(int i=0; i<nticks; i++){
980 tickchar[i] = String.valueOf(tickval[i]);
981 tickchar[i] = tickchar[i].trim();
982 }
983
984 return nticks;
985 }
986
987 // Find minimum and maximum x and y values
988 public void minMax(){
989 boolean test = true;
990
991 int ii=0;
992 while(test){
993 if(this.minMaxOpt[ii]){
994 test=false;
995 this.xMin=this.data[2*ii][0];
996 this.xMax=this.data[2*ii][0];
997 this.yMin=this.data[2*ii+1][0];
998 if(this.errorBar[ii])this.yMin=2.0D*this.yMin-this.errors[ii][0];
999 this.yMax=this.data[2*ii+1][0];
1000 if(this.errorBar[ii])this.yMax=errors[ii][0];
1001 }
1002 else{
1003 ii++;
1004 if(ii>nCurves)throw new IllegalArgumentException("At least one curve must be included in the maximum/minimum calculation");
1005 }
1006 }
1007
1008 int k=0;
1009 double yMint=0.0D, yMaxt=0.0D;
1010 for(int i=0; i<this.nCurves; i++){
1011 if(minMaxOpt[i]){
1012 for(int j=0; j<this.nPoints[i]; j++){
1013 if(this.xMin>this.data[k][j])this.xMin=this.data[k][j];
1014 if(this.xMax<this.data[k][j])this.xMax=this.data[k][j];
1015 yMint=this.data[k+1][j];
1016 if(errorBar[i])yMint=2.0D*yMint-errors[i][j];
1017 if(this.yMin>yMint)this.yMin=yMint;
1018 yMaxt=this.data[k+1][j];
1019 if(errorBar[i])yMaxt=errors[i][j];
1020 if(this.yMax<yMaxt)this.yMax=yMaxt;
1021 }
1022 }
1023 k+=2;
1024 }
1025
1026 if(this.xMin==this.xMax){
1027 if(this.xMin==0.0D){
1028 this.xMin=0.1D;
1029 this.xMax=0.1D;
1030 }
1031 else{
1032 if(this.xMin<0.0D){
1033 this.xMin=this.xMin*1.1D;
1034 }
1035 else{
1036 this.xMax=this.xMax*1.1D;
1037 }
1038 }
1039 }
1040
1041 if(this.yMin==this.yMax){
1042 if(this.yMin==0.0D){
1043 this.yMin=0.1D;
1044 this.yMax=0.1D;
1045 }
1046 else{
1047 if(this.yMin<0.0D){
1048 this.yMin=this.yMin*1.1D;
1049 }
1050 else{
1051 this.yMax=this.yMax*1.1D;
1052 }
1053 }
1054 }
1055 }
1056
1057 // Convert offset value to a string and reformat if in E format
1058 protected static String offsetString(double offset){
1059 String stroffset = String.valueOf(offset);
1060 String substr1="", substr2="", substr3="";
1061 String zero ="0";
1062 int posdot = stroffset.indexOf('.');
1063 int posexp = stroffset.indexOf('E');
1064
1065 if(posexp==-1){
1066 return stroffset;
1067 }
1068 else{
1069 substr1 = stroffset.substring(posexp+1);
1070 int n = Integer.parseInt(substr1);
1071 substr1 = stroffset.substring(0,posexp);
1072 if(n>=0){
1073 for(int i=0; i<n; i++){
1074 substr1 = substr1 + zero;
1075 }
1076 return substr1;
1077 }
1078 else{
1079 substr2 = substr1.substring(0, posdot+1);
1080 substr3 = substr1.substring(posdot+1);
1081 for(int i=0; i<-n; i++){
1082 substr2 = substr1 + zero;
1083 }
1084 substr2 = substr2 + substr3;
1085 return substr2;
1086 }
1087 }
1088 }
1089
1090 // check whether point in line segment is to be drawn
1091 public boolean printCheck(boolean trim, int xoldpoint, int xnewpoint, int yoldpoint, int ynewpoint){
1092
1093 boolean btest2=true;
1094
1095 if(trim){
1096 if(xoldpoint<xBot)btest2=false;
1097 if(xoldpoint>xTop)btest2=false;
1098 if(xnewpoint<xBot)btest2=false;
1099 if(xnewpoint>xTop)btest2=false;
1100 if(yoldpoint>yBot)btest2=false;
1101 if(yoldpoint<yTop)btest2=false;
1102 if(ynewpoint>yBot)btest2=false;
1103 if(ynewpoint<yTop)btest2=false;
1104 }
1105
1106 return btest2;
1107 }
1108
1109 // Draw graph
1110 public void graph(Graphics g){
1111
1112 // Set font type and size
1113 g.setFont(new Font("serif", Font.PLAIN, this.fontSize));
1114 FontMetrics fm = g.getFontMetrics();
1115
1116 // calculation of all graphing parameters and data scaling
1117 axesScaleOffset();
1118
1119 // Draw title, legends and axes
1120 String xoffstr = offsetString(xOffset);
1121 String yoffstr = offsetString(yOffset);
1122 String bunit1 = " /( ";
1123 String bunit2 = " )";
1124 String bunit3 = " / ";
1125 String bunit4 = " ";
1126 String bunit5 = " x 10";
1127 String bunit6 = "10";
1128 String nounit = " ";
1129 String xbrack1 = bunit1;
1130 String xbrack2 = bunit2;
1131 String xbrack3 = bunit5;
1132 if(this.xFac==0){
1133 xbrack1 = bunit3;
1134 xbrack2 = "";
1135 xbrack3 = "";
1136 }
1137 String ybrack1 = bunit1;
1138 String ybrack2 = bunit2;
1139 String ybrack3 = bunit5;
1140 if(this.yFac==0){
1141 ybrack1 = bunit3;
1142 ybrack2 = "";
1143 ybrack3 = "";
1144 }
1145 if(noXunits){
1146 if(xFac==0){
1147 xbrack1=nounit;
1148 xbrack2=nounit;
1149 xbrack3=nounit;
1150 }
1151 else{
1152 xbrack1=bunit3;
1153 xbrack2=bunit4;
1154 xbrack3=bunit6;
1155 }
1156 }
1157 if(noYunits){
1158 if(yFac==0){
1159 ybrack1=nounit;
1160 ybrack2=nounit;
1161 ybrack3=nounit;
1162 }
1163 else{
1164 ybrack1=bunit3;
1165 ybrack2=bunit4;
1166 ybrack3=bunit6;
1167 }
1168 }
1169
1170 double xLen=xTop-xBot;
1171 double yLen=yBot-yTop;
1172
1173 // Print title
1174 String sp = " + ", sn = " - ";
1175 String ss=sn;
1176 g.drawString(this.graphTitle+" ", 15,15);
1177 g.drawString(this.graphTitle2+" ", 15,35);
1178 if(this.xOffset<0){
1179 ss=sp;
1180 xOffset=-xOffset;
1181 }
1182
1183 // Print legends
1184 int sw=0;
1185 String ssx="", ssy="", sws1="", sws2="";
1186 if(this.xFac==0 && this.xOffset==0){
1187 g.drawString(this.xAxisLegend+xbrack1+this.xAxisUnits+xbrack2, xBot-4,yBot+32);
1188 }
1189 else{
1190 if(this.xOffset==0){
1191 ssx = this.xAxisLegend + xbrack1 + this.xAxisUnits + xbrack3;
1192 sw = fm.stringWidth(ssx);
1193 g.drawString(ssx, xBot-4,yBot+42);
1194 sws1=String.valueOf(-this.xFac-1);
1195 g.drawString(sws1, xBot-4+sw+1,yBot+32);
1196 sw += fm.stringWidth(sws1);
1197 g.drawString(xbrack2, xBot-4+sw+1,yBot+42);
1198 }
1199 else{
1200 if(this.xFac==0){
1201 g.drawString(this.xAxisLegend + ss + xoffstr + xbrack1+this.xAxisUnits+xbrack2, xBot-4,yBot+30);
1202 }
1203 else{
1204 ssx = this.xAxisLegend + ss + xoffstr + xbrack1+this.xAxisUnits+xbrack3;
1205 sw = fm.stringWidth(ssx);
1206 g.drawString(ssx, xBot-4,yBot+37);
1207 sws1 = String.valueOf(-this.xFac-1);
1208 g.drawString(sws1, xBot-4+sw+1,yBot+32);
1209 sw += fm.stringWidth(sws1);
1210 g.drawString(xbrack2, xBot-4+sw+1,yBot+37);
1211 }
1212 }
1213 }
1214
1215 ss=sn;
1216 if(yOffset<0){
1217 ss=sp;
1218 yOffset=-yOffset;
1219 }
1220
1221 if(yFac==0 && yOffset==0){
1222 g.drawString(this.yAxisLegend+" ", 15,yTop-25);
1223 g.drawString(ybrack1+this.yAxisUnits+ybrack2, 15,yTop-10);
1224 }
1225 else{
1226 if(yOffset==0){
1227 g.drawString(this.yAxisLegend, 15,yTop-35);
1228 sws1 = ybrack1+this.yAxisUnits + ybrack3;
1229 g.drawString(sws1, 15,yTop-15);
1230 sw = fm.stringWidth(sws1);
1231 sws2=String.valueOf(-this.yFac-1);
1232 g.drawString(sws2, 15+sw+1,yTop-20);
1233 sw += fm.stringWidth(sws2);
1234 g.drawString(ybrack2, 15+sw+1,yTop-15);
1235 }
1236 else{
1237 if(yFac==0){
1238 g.drawString(this.yAxisLegend + ss + yoffstr, 15,yTop-25);
1239 g.drawString(ybrack1+this.yAxisUnits+ybrack2, 15,yTop-10);
1240 }
1241 else{
1242 ssy = this.yAxisLegend + ss + yoffstr;
1243 g.drawString(ssy, 15,yTop-35);
1244 sws1 = ybrack1+this.yAxisUnits + ybrack3;
1245 g.drawString(sws1, 15,yTop-15);
1246 sw = fm.stringWidth(sws1);
1247 sws2=String.valueOf(-this.yFac-1);
1248 g.drawString(sws2, 15+sw+1,yTop-20);
1249 sw += fm.stringWidth(sws2);
1250 g.drawString(ybrack2, 15+sw+1,yTop-15);
1251 }
1252 }
1253 }
1254
1255 // Draw axes
1256 int zdif=0, zold=0, znew=0, zzer=0;
1257 double csstep=0.0D;
1258 double xdenom=(xHigh-xLow);
1259 double ydenom=(yHigh-yLow);
1260
1261 g.drawLine(xBot, yBot, xTop, yBot);
1262 g.drawLine(xBot, yTop, xTop, yTop);
1263 g.drawLine(xBot, yBot, xBot, yTop);
1264 g.drawLine(xTop, yBot, xTop, yTop);
1265
1266
1267 // Draw zero lines if drawn axes are not at zero and a zero value lies on an axis
1268 if(xZero){
1269 zdif=8;
1270 zzer=xBot+(int)(((0.0-xLow)/xdenom)*xLen);
1271 g.drawLine(zzer,yTop,zzer,yTop+8);
1272 g.drawLine(zzer,yBot,zzer,yBot-8);
1273 zold=yTop;
1274 while(zold+zdif<yBot){
1275 znew=zold+zdif;
1276 g.drawLine(zzer, zold, zzer, znew);
1277 zold=znew+zdif;
1278 }
1279 }
1280
1281 if(yZero){
1282 zdif=8;
1283 zzer=yBot-(int)(((0.0-yLow)/ydenom)*yLen);
1284 g.drawLine(xBot,zzer,xBot+8,zzer);
1285 g.drawLine(xTop,zzer,xTop-8,zzer);
1286 zold=xBot;
1287 while(zold+zdif<xTop){
1288 znew=zold+zdif;
1289 g.drawLine(zold, zzer, znew, zzer);
1290 zold=znew+zdif;
1291 }
1292 }
1293
1294 // Draw tick marks and axis numbers
1295 int xt=0;
1296 //double xtep=(double)(xTop-xBot)/((double)(this.xTicks-1));
1297 for(int ii=0; ii<this.xTicks; ii++)
1298 {
1299 xt=xBot+(int)(((this.xAxisNo[ii]-xLow)/xdenom)*xLen);
1300 g.drawLine(xt,yBot,xt,yBot-8);
1301 g.drawLine(xt,yTop,xt,yTop+8);
1302 g.drawString(xAxisChar[ii]+" ",xt-4,yBot+18);
1303 }
1304
1305 int yt=0;
1306 int yCharLenMax=yAxisChar[0].length();
1307 for(int ii=1; ii<this.yTicks; ii++)if(yAxisChar[ii].length()>yCharLenMax)yCharLenMax=yAxisChar[ii].length();
1308 int shift = (yCharLenMax-3)*5;
1309 double ytep=(double)(-yTop+yBot)/((double)(this.yTicks-1));
1310 for(int ii=0; ii<this.yTicks; ii++)
1311 {
1312 yt=yBot-(int)Math.round(ii*ytep);
1313 yt=yBot-(int)(((this.yAxisNo[ii]-yLow)/ydenom)*yLen);
1314 g.drawLine(xBot,yt,xBot+8,yt);
1315 g.drawLine(xTop,yt,xTop-8,yt);
1316 g.drawString(yAxisChar[ii]+" ",xBot-30-shift,yt+4);
1317 }
1318
1319 int dsum=0; // dashed line counter
1320 boolean dcheck=true; // dashed line check
1321
1322 // Draw curves
1323 int kk=0;
1324 int xxp=0, yyp=0, yype=0;
1325 int xoldpoint=0, xnewpoint=0, yoldpoint=0, ynewpoint=0;
1326 int ps=0, psh=0, nxpoints=0;
1327 double ics[]= new double[niPoints];
1328 boolean btest2=true;
1329
1330 for(int i=0; i<this.nCurves; i++){
1331 // cubic spline interpolation option
1332 nxpoints=this.nPoints[i];
1333 double xcs[]= new double[nxpoints];
1334 double ycs[]= new double[nxpoints];
1335
1336 if(lineOpt[i]==1 || lineOpt[i]==2){
1337 CubicSpline cs = new CubicSpline(this.nPoints[i]);
1338 for(int ii=0; ii<nxpoints; ii++){
1339 xcs[ii]=this.data[kk][ii];
1340 }
1341 csstep=(xcs[nxpoints-1]-xcs[0])/(niPoints-1);
1342 ics[0]=xcs[0];
1343 for(int ii=1; ii<niPoints; ii++){
1344 ics[ii]=ics[ii-1]+csstep;
1345 }
1346 ics[niPoints-1] = xcs[nxpoints-1];
1347 for(int ii=0; ii<nxpoints; ii++){
1348 ycs[ii]=this.data[kk+1][ii];
1349 }
1350
1351 cs.resetData(xcs, ycs);
1352 cs.calcDeriv();
1353 xoldpoint=xBot+(int)(((xcs[0]-xLow)/xdenom)*xLen);
1354 yoldpoint=yBot-(int)(((ycs[0]-yLow)/ydenom)*yLen);
1355 for(int ii=1; ii<niPoints; ii++){
1356 xnewpoint=xBot+(int)(((ics[ii]-xLow)/xdenom)*xLen);
1357 ynewpoint=yBot-(int)(((cs.interpolate(ics[ii])-yLow)/ydenom)*yLen);
1358 btest2=printCheck(trimOpt[i], xoldpoint, xnewpoint, yoldpoint, ynewpoint);
1359 if(btest2){
1360 if(this.lineOpt[i]==2){
1361 dsum++;
1362 if(dsum>dashLength[i]){
1363 dsum=0;
1364 if(dcheck){
1365 dcheck=false;
1366 }
1367 else{
1368 dcheck=true;
1369 }
1370 }
1371 }
1372 if(dcheck)g.drawLine(xoldpoint,yoldpoint,xnewpoint,ynewpoint);
1373 }
1374 xoldpoint=xnewpoint;
1375 yoldpoint=ynewpoint;
1376 }
1377 }
1378
1379 if(lineOpt[i]==-1 || lineOpt[i]==-2){
1380 CubicSpline cs = new CubicSpline(this.nPoints[i]);
1381 for(int ii=0; ii<nxpoints; ii++){
1382 xcs[ii]=this.data[kk][ii];
1383 }
1384 for(int ii=0; ii<nxpoints; ii++){
1385 ycs[ii]=this.data[kk+1][ii];
1386 }
1387 csstep=(ycs[nxpoints-1]-ycs[0])/(niPoints-1);
1388 ics[0]=ycs[0];
1389 for(int ii=1; ii<niPoints; ii++){
1390 ics[ii]=ics[ii-1]+csstep;
1391 }
1392 ics[niPoints-1] = ycs[nxpoints-1];
1393
1394 cs.resetData(ycs, xcs);
1395 cs.calcDeriv();
1396 xoldpoint=xBot+(int)(((xcs[0]-xLow)/xdenom)*xLen);
1397 yoldpoint=yBot-(int)(((ycs[0]-yLow)/ydenom)*yLen);
1398 for(int ii=1; ii<niPoints; ii++){
1399 ynewpoint=yBot+(int)(((ics[ii]-yLow)/ydenom)*yLen);
1400 xnewpoint=xBot-(int)(((cs.interpolate(ics[ii])-xLow)/xdenom)*xLen);
1401 btest2=printCheck(trimOpt[i], xoldpoint, xnewpoint, yoldpoint, ynewpoint);
1402 if(btest2){
1403 if(this.lineOpt[i]==2){
1404 dsum++;
1405 if(dsum>dashLength[i]){
1406 dsum=0;
1407 if(dcheck){
1408 dcheck=false;
1409 }
1410 else{
1411 dcheck=true;
1412 }
1413 }
1414 }
1415 if(dcheck)g.drawLine(xoldpoint,yoldpoint,xnewpoint,ynewpoint);
1416 }
1417 xoldpoint=xnewpoint;
1418 yoldpoint=ynewpoint;
1419 }
1420 }
1421
1422 if(lineOpt[i]==3){
1423 // Join points option
1424 dsum=0;
1425 dcheck=true;
1426 xoldpoint=xBot+(int)((((this.data[kk][0])-xLow)/xdenom)*xLen);
1427 yoldpoint=yBot-(int)((((this.data[kk+1][0])-yLow)/ydenom)*yLen);
1428 for(int ii=1; ii<nxpoints; ii++){
1429 xnewpoint=xBot+(int)((((this.data[kk][ii])-xLow)/xdenom)*xLen);
1430 ynewpoint=yBot-(int)((((this.data[kk+1][ii])-yLow)/ydenom)*yLen);
1431 btest2=printCheck(trimOpt[i], xoldpoint, xnewpoint, yoldpoint, ynewpoint);
1432 if(btest2)g.drawLine(xoldpoint,yoldpoint,xnewpoint,ynewpoint);
1433 xoldpoint=xnewpoint;
1434 yoldpoint=ynewpoint;
1435 }
1436 }
1437
1438 if(lineOpt[i]==4){
1439 // Join points with dotted line option
1440
1441 // lines between points
1442 int[] lengths = new int[nxpoints-1];
1443 double[] gradients = new double[nxpoints-1];
1444 double[] intercepts = new double[nxpoints-1];
1445 int totalLength = 0;
1446 xoldpoint=xBot+(int)((((this.data[kk][0])-xLow)/xdenom)*xLen);
1447 yoldpoint=yBot-(int)((((this.data[kk+1][0])-yLow)/ydenom)*yLen);
1448 for(int ii=1; ii<nxpoints; ii++){
1449 xnewpoint=xBot+(int)((((this.data[kk][ii])-xLow)/xdenom)*xLen);
1450 ynewpoint=yBot-(int)((((this.data[kk+1][ii])-yLow)/ydenom)*yLen);
1451 lengths[ii-1] = (int)Fmath.hypot((double)(xnewpoint-xoldpoint), (double)(ynewpoint-yoldpoint));
1452 totalLength += lengths[ii-1];
1453 gradients[ii-1] = (double)(ynewpoint-yoldpoint)/(double)(xnewpoint-xoldpoint);
1454 intercepts[ii-1] = (double)yoldpoint - gradients[ii-1]*xoldpoint;
1455 xoldpoint=xnewpoint;
1456 yoldpoint=ynewpoint;
1457 }
1458
1459 // number of points
1460 int incrmt = totalLength/(4*niPoints-1);
1461 int nlpointsold = 0;
1462 int nlpointsnew = 0;
1463 int totalLpoints = 1;
1464 for(int ii=1; ii<nxpoints; ii++){
1465 totalLpoints++;
1466 nlpointsnew = lengths[ii-1]/incrmt;
1467 for(int jj = nlpointsold+1; jj<(nlpointsnew + nlpointsold); jj++)totalLpoints ++;
1468 nlpointsold = nlpointsold + nlpointsnew;
1469 }
1470
1471 // fill arrays
1472 int[] xdashed = new int[totalLpoints];
1473 int[] ydashed = new int[totalLpoints];
1474 nlpointsold = 0;
1475 nlpointsnew = 0;
1476 xdashed[0] = xBot+(int)((((this.data[kk][0])-xLow)/xdenom)*xLen);
1477 ydashed[0] = yBot-(int)((((this.data[kk+1][0])-yLow)/ydenom)*yLen);
1478 for(int ii=1; ii<nxpoints; ii++){
1479 nlpointsnew = lengths[ii-1]/incrmt;
1480 xdashed[nlpointsnew + nlpointsold] = xBot+(int)((((this.data[kk][ii])-xLow)/xdenom)*xLen);
1481 ydashed[nlpointsnew + nlpointsold] = yBot-(int)((((this.data[kk+1][ii])-yLow)/ydenom)*yLen);
1482 if(Math.abs(gradients[ii-1])>0.5){
1483 int diff = (ydashed[nlpointsnew + nlpointsold] - ydashed[nlpointsold])/nlpointsnew;
1484 for(int jj = nlpointsold+1; jj<(nlpointsnew + nlpointsold); jj++){
1485 ydashed[jj] = ydashed[jj-1]+diff;
1486 if(Fmath.isInfinity(Math.abs(gradients[ii-1]))){
1487 xdashed[jj] = xdashed[nlpointsnew + nlpointsold];
1488 }
1489 else{
1490 xdashed[jj] = (int)(((double)ydashed[jj] - intercepts[ii-1])/gradients[ii-1]);
1491 }
1492 }
1493 }
1494 else{
1495 int diff = (xdashed[nlpointsnew + nlpointsold] - xdashed[nlpointsold])/nlpointsnew;
1496 for(int jj = nlpointsold+1; jj<(nlpointsnew + nlpointsold); jj++){
1497 xdashed[jj] = xdashed[jj-1]+diff;
1498 ydashed[jj] = (int)(gradients[ii-1]*ydashed[jj] + intercepts[ii-1]);
1499 }
1500 }
1501 nlpointsold = nlpointsold + nlpointsnew;
1502 }
1503
1504 dsum=0;
1505 dcheck=true;
1506 for(int ii=1; ii<totalLpoints; ii++){
1507 dsum++;
1508 if(dsum>dashLength[i]){
1509 dsum=0;
1510 if(dcheck){
1511 dcheck=false;
1512 }
1513 else{
1514 dcheck=true;
1515 }
1516 }
1517 if(dcheck)g.drawLine(xdashed[ii-1],ydashed[ii-1],xdashed[ii],ydashed[ii]);
1518 }
1519 }
1520
1521
1522
1523 // Plot points
1524 if(pointOpt[i]>0){
1525 for(int ii=0; ii<nxpoints; ii++){
1526 ps=this.pointSize[i];
1527 psh=ps/2;
1528 xxp=xBot+(int)(((this.data[kk][ii]-xLow)/xdenom)*xLen);
1529 yyp=yBot-(int)(((this.data[kk+1][ii]-yLow)/ydenom)*yLen);
1530 switch(pointOpt[i]){
1531 case 1: g.drawOval(xxp-psh, yyp-psh, ps, ps);
1532 break;
1533 case 2: g.drawRect(xxp-psh, yyp-psh, ps, ps);
1534 break;
1535 case 3: g.drawLine(xxp-psh, yyp, xxp, yyp+psh);
1536 g.drawLine(xxp, yyp+psh, xxp+psh, yyp);
1537 g.drawLine(xxp+psh, yyp, xxp, yyp-psh);
1538 g.drawLine(xxp, yyp-psh, xxp-psh, yyp);
1539 break;
1540 case 4: g.fillOval(xxp-psh, yyp-psh, ps, ps);
1541 break;
1542 case 5: g.fillRect(xxp-psh, yyp-psh, ps, ps);
1543 break;
1544 case 6: for(int jj=0; jj<psh; jj++)g.drawLine(xxp-jj, yyp-psh+jj, xxp+jj, yyp-psh+jj);
1545 for(int jj=0; jj<=psh; jj++)g.drawLine(xxp-psh+jj, yyp+jj, xxp+psh-jj, yyp+jj);
1546 break;
1547 case 7: g.drawLine(xxp-psh, yyp-psh, xxp+psh, yyp+psh);
1548 g.drawLine(xxp-psh, yyp+psh, xxp+psh, yyp-psh);
1549 break;
1550 case 8: g.drawLine(xxp-psh, yyp, xxp+psh, yyp);
1551 g.drawLine(xxp, yyp+psh, xxp, yyp-psh);
1552 break;
1553 default:g.drawLine(xxp-psh, yyp-psh, xxp+psh, yyp+psh);
1554 g.drawLine(xxp-psh, yyp+psh, xxp+psh, yyp-psh);
1555 break;
1556 }
1557
1558 if(this.errorBar[i]){
1559 yype=yBot-(int)(((errors[i][ii]-yLow)/ydenom)*yLen);
1560 g.drawLine(xxp, yyp, xxp, yype);
1561 g.drawLine(xxp-4, yype, xxp+4, yype);
1562 yype=2*yyp-yype;
1563 g.drawLine(xxp, yyp, xxp, yype);
1564 g.drawLine(xxp-4, yype, xxp+4, yype);
1565 }
1566 }
1567 }
1568 kk+=2;
1569 }
1570 }
1571
1572 // Return the serial version unique identifier
1573 public static long getSerialVersionUID(){
1574 return Plot.serialVersionUID;
1575 }
1576}
Note: See TracBrowser for help on using the repository browser.