1 package JSci.swing; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import java.awt.geom.Point2D ; 6 import java.text.DecimalFormat ; 7 import java.text.NumberFormat ; 8 import java.text.ParseException ; 9 import java.util.Iterator ; 10 import java.util.List ; 11 import java.util.ArrayList ; 12 import JSci.awt.*;import JSci.maths.ExtraMath; 13 14 19 public final class JLineTrace extends JDoubleBufferedComponent { 20 23 private final List dataPoints = new ArrayList (); 24 27 private float samplingInterval; 28 31 private boolean numbering=true; 32 private NumberFormat xNumberFormat = new DecimalFormat ("##0.0"); 33 private NumberFormat yNumberFormat = new DecimalFormat ("##0.0"); 34 37 private Point origin=new Point(); 38 41 private float minX,minY,maxX,maxY; 42 45 private float xScale,yScale; 46 private final float xIncPixels = 40.0f; 47 private final float yIncPixels = 40.0f; 48 51 private final int scalePad=5; 52 private final int axisPad=25; 53 private int leftAxisPad; 54 57 public JLineTrace(float minx,float maxx,float miny,float maxy) { 58 addMouseMotionListener(new MouseLineAdapter()); 59 setXExtrema(minx,maxx); 60 setYExtrema(miny,maxy); 61 setSamplingInterval(0.2f); 62 } 63 66 public Graph2DModel getModel() { 67 final Point2DListModel model=new Point2DListModel(); 68 model.setData(dataPoints); 69 return model; 70 } 71 74 public final void setNumbering(boolean flag) { 75 numbering=flag; 76 leftAxisPad=axisPad; 77 if(numbering && getFont() != null) { 78 final FontMetrics metrics = getFontMetrics(getFont()); 80 final int maxYNumLen = metrics.stringWidth(yNumberFormat.format(maxY)); 81 final int minYNumLen = metrics.stringWidth(yNumberFormat.format(minY)); 82 int yNumPad = Math.max(minYNumLen, maxYNumLen); 83 if(minX<0.0f) { 84 final int negXLen = (int)((Math.max(getSize().width,getMinimumSize().width)-2*(axisPad+scalePad))*minX/(minX-maxX)); 85 yNumPad = Math.max(yNumPad-negXLen, 0); 86 } 87 leftAxisPad += yNumPad; 88 } 89 } 90 public void addNotify() { 91 super.addNotify(); 92 setNumbering(numbering); 95 } 96 102 public final void setNumberFormat(NumberFormat format) { 103 xNumberFormat = format; 104 yNumberFormat = format; 105 setNumbering(numbering); 106 } 107 110 public final void setXNumberFormat(NumberFormat format) { 111 xNumberFormat = format; 112 setNumbering(numbering); 113 } 114 117 public final void setYNumberFormat(NumberFormat format) { 118 yNumberFormat = format; 119 setNumbering(numbering); 120 } 121 124 public void setXExtrema(float min,float max) { 125 if(max<min) 126 throw new IllegalArgumentException ("Maximum should be greater than minimum; max = "+max+" and min = "+min); 127 minX=min; 128 maxX=max; 129 rescale(); 130 } 131 134 public void setYExtrema(float min,float max) { 135 if(max<min) 136 throw new IllegalArgumentException ("Maximum should be greater than minimum; max = "+max+" and min = "+min); 137 minY=min; 138 maxY=max; 139 rescale(); 140 } 141 145 public void setSamplingInterval(float interval) { 146 samplingInterval = interval; 147 } 148 151 public void clear() { 152 dataPoints.clear(); 153 redraw(); 154 } 155 158 public final void setBounds(int x,int y,int width,int height) { 159 super.setBounds(x,y,width,height); 160 rescale(); 161 } 162 165 private void rescale() { 166 final Dimension s=getMinimumSize(); 167 final int thisWidth=Math.max(getWidth(),s.width); 169 final int thisHeight=Math.max(getHeight(),s.height); 170 xScale = (float) ((double)(thisWidth-(leftAxisPad+axisPad)) / (double)(maxX-minX)); 171 yScale = (float) ((double)(thisHeight-2*axisPad) / (double)(maxY-minY)); 172 origin.x=leftAxisPad-Math.round(minX*xScale); 173 origin.y=thisHeight-axisPad+Math.round(minY*yScale); 174 redraw(); 175 } 176 179 public Dimension getPreferredSize() { 180 return getMinimumSize(); 181 } 182 185 public Dimension getMinimumSize() { 186 return new Dimension(200,200); 187 } 188 191 private Point2D.Float screenToData(Point p) { 192 double x = (double)(p.x-origin.x) / (double)xScale; 193 double y = (double)(origin.y-p.y) / (double)yScale; 194 return new Point2D.Float ((float)x, (float)y); 195 } 196 199 private Point dataToScreen(Point2D.Float p) { 200 return new Point(origin.x+Math.round(xScale*p.x),origin.y-Math.round(yScale*p.y)); 201 } 202 private Point dataToScreen(float x, float y) { 203 return new Point(origin.x+Math.round(xScale*x),origin.y-Math.round(yScale*y)); 204 } 205 208 protected void offscreenPaint(Graphics g) { 209 drawAxes(g); 210 Point p1,p2; 212 Iterator iter = dataPoints.iterator(); 213 if(iter.hasNext()) { 214 p1 = dataToScreen((Point2D.Float ) iter.next()); 215 while(iter.hasNext()) { 216 p2 = dataToScreen((Point2D.Float ) iter.next()); 217 g.drawLine(p1.x, p1.y, p2.x, p2.y); 218 p1 = p2; 219 } 220 } 221 } 222 225 private void drawAxes(Graphics g) { 226 g.setColor(getForeground()); 228 if(minY>0.0f) 229 g.drawLine(leftAxisPad-scalePad,getHeight()-axisPad,getWidth()-(axisPad-scalePad),getHeight()-axisPad); 230 else 231 g.drawLine(leftAxisPad-scalePad,origin.y,getWidth()-(axisPad-scalePad),origin.y); 232 if(minX>0.0f) 233 g.drawLine(leftAxisPad,axisPad-scalePad,leftAxisPad,getHeight()-(axisPad-scalePad)); 234 else 235 g.drawLine(origin.x,axisPad-scalePad,origin.x,getHeight()-(axisPad-scalePad)); 236 if(numbering) { 238 final FontMetrics metrics=g.getFontMetrics(); 239 final int strHeight=metrics.getHeight(); 240 float dx = (float) ExtraMath.round((double)xIncPixels/(double)xScale, 1); 242 if(dx == 0.0f) 243 dx = Float.MIN_VALUE; 244 for(double x=(minX>0.0f)?minX:dx; x<=maxX; x+=dx) { 245 String str = xNumberFormat.format((float)x); 246 int strWidth=metrics.stringWidth('+'+str); 248 Point p=dataToScreen((float)x, (minY>0.0f)?minY:0.0f); 249 g.drawLine(p.x,p.y,p.x,p.y+5); 250 g.drawString(str,p.x-strWidth/2,p.y+5+strHeight); 251 } 252 for(double x=-dx; x>=minX; x-=dx) { 253 String str = xNumberFormat.format((float)x); 254 int strWidth=metrics.stringWidth(str); 255 Point p=dataToScreen((float)x, (minY>0.0f)?minY:0.0f); 256 g.drawLine(p.x,p.y,p.x,p.y+5); 257 g.drawString(str,p.x-strWidth/2,p.y+5+strHeight); 258 } 259 float dy = (float) ExtraMath.round((double)yIncPixels/(double)yScale, 1); 261 if(dy == 0.0f) 262 dy = Float.MIN_VALUE; 263 for(double y=(minY>0.0f)?minY:dy; y<=maxY; y+=dy) { 264 String str = yNumberFormat.format((float)y); 265 int strWidth=metrics.stringWidth(str); 266 Point p=dataToScreen((minX>0.0f)?minX:0.0f, (float)y); 267 g.drawLine(p.x,p.y,p.x-5,p.y); 268 g.drawString(str,p.x-8-strWidth,p.y+strHeight/4); 269 } 270 for(double y=-dy; y>=minY; y-=dy) { 271 String str = yNumberFormat.format((float)y); 272 int strWidth=metrics.stringWidth(str); 273 Point p=dataToScreen((minX>0.0f)?minX:0.0f, (float)y); 274 g.drawLine(p.x,p.y,p.x-5,p.y); 275 g.drawString(str,p.x-8-strWidth,p.y+strHeight/4); 276 } 277 } 278 } 279 class MouseLineAdapter extends MouseMotionAdapter { 280 public void mouseDragged(MouseEvent evt) { 281 Point2D.Float p=screenToData(evt.getPoint()); 282 final int i = dataPoints.size()-1; 283 if(p.x >= i*samplingInterval+minX && p.x <= maxX) { 284 dataPoints.add(p); 285 } 286 redraw(); 287 } 288 } 289 } 290
| Popular Tags
|