001package hw4; 002 003import java.awt.Canvas; 004import java.awt.Color; 005import java.awt.Graphics; 006 007/** 008 * <b>PolyGraph</b> is part of the graphical calculator that utilizes all of 009 * the other classes in package hw4. PolyGraph implements the graphing 010 * component. 011 * 012 * @author Felix Klock, Andreas Hofmann 013 * @version 1.0 014 */ 015public final class PolyGraph extends Canvas { 016 Color col[] = new Color[4]; 017 018 Color zeroline = new Color(0xe0, 0xe0, 0xff); 019 020 CalculatorFrame calcFrame; 021 022 // Serializable classes are supposed to have this 023 private static final long serialVersionUID = 24L; 024 025 public PolyGraph(CalculatorFrame cf) { 026 super(); 027 028 calcFrame = cf; 029 030 col[0] = new Color(0xa0, 0, 0); 031 col[1] = new Color(0, 0, 0xFF); 032 col[2] = new Color(0, 0x80, 0); 033 col[3] = new Color(0, 0, 0); 034 } 035 036 @Override 037 public void update(Graphics g) { 038 paint(g); 039 } 040 041 @Override 042 public void paint(Graphics g) { 043 int w = getSize().width; 044 int h = getSize().height; 045 046 g.setColor(Color.white); 047 g.fillRect(0, 0, w, h); 048 049 /* 050 * g.setColor(Color.red); String msg= "Click to graph selected 051 * variable"; int wid= getFontMetrics(getFont()).stringWidth(msg); 052 * g.drawString(msg, (w-wid)/2, h/2); 053 */ 054 055 // Draw axes and data 056 int numIncrements = 100; 057 058 float xMin = Float.parseFloat(calcFrame.jTextField1.getText()); 059 float xMax = Float.parseFloat(calcFrame.jTextField2.getText()); 060 float yMin = 0; 061 float yMax = 0; 062 float[] xValBuffer1 = null; 063 float[] yValBuffer1 = null; 064 float[] xValBuffer2 = null; 065 float[] yValBuffer2 = null; 066 float[] xValBuffer3 = null; 067 float[] yValBuffer3 = null; 068 float[] xValBuffer4 = null; 069 float[] yValBuffer4 = null; 070 float[] yExtrema; 071 String msg; 072 073 if (xMin >= xMax) { 074 g.setColor(Color.red); 075 msg = "Xmin must be greater than Xmax"; 076 int wid = getFontMetrics(getFont()).stringWidth(msg); 077 g.drawString(msg, (w - wid) / 2, h / 2); 078 return; 079 } 080 081 // Get RatPoly 082 RatPoly currentRatPoly; 083 084 // Now fill in new information base on what's in stack. 085 // Note that size of stack must be checked. 086 if ((calcFrame.stack != null) && (calcFrame.stack.size() > 0)) { 087 currentRatPoly = calcFrame.stack.getNthFromTop(0); 088 xValBuffer1 = new float[numIncrements]; 089 yValBuffer1 = new float[numIncrements]; 090 yExtrema = new float[2]; 091 } else { 092 g.setColor(Color.red); 093 msg = "Stack is empty"; 094 int wid = getFontMetrics(getFont()).stringWidth(msg); 095 g.drawString(msg, (w - wid) / 2, h / 2); 096 return; 097 } 098 099 updatePlotBuffer(xMin, xMax, numIncrements, xValBuffer1, yValBuffer1, 100 yExtrema, currentRatPoly); 101 102 yMin = yExtrema[0]; 103 yMax = yExtrema[1]; 104 105 if (calcFrame.stack.size() > 1) { 106 currentRatPoly = calcFrame.stack.getNthFromTop(1); 107 xValBuffer2 = new float[numIncrements]; 108 yValBuffer2 = new float[numIncrements]; 109 110 updatePlotBuffer(xMin, xMax, numIncrements, xValBuffer2, 111 yValBuffer2, yExtrema, currentRatPoly); 112 113 if (yExtrema[0] < yMin) { 114 yMin = yExtrema[0]; 115 } 116 117 if (yExtrema[1] > yMax) { 118 yMax = yExtrema[1]; 119 } 120 } 121 122 if (calcFrame.stack.size() > 2) { 123 currentRatPoly = calcFrame.stack.getNthFromTop(2); 124 xValBuffer3 = new float[numIncrements]; 125 yValBuffer3 = new float[numIncrements]; 126 127 updatePlotBuffer(xMin, xMax, numIncrements, xValBuffer3, 128 yValBuffer3, yExtrema, currentRatPoly); 129 130 if (yExtrema[0] < yMin) { 131 yMin = yExtrema[0]; 132 } 133 134 if (yExtrema[1] > yMax) { 135 yMax = yExtrema[1]; 136 } 137 } 138 139 if (calcFrame.stack.size() > 3) { 140 currentRatPoly = calcFrame.stack.getNthFromTop(3); 141 xValBuffer4 = new float[numIncrements]; 142 yValBuffer4 = new float[numIncrements]; 143 144 updatePlotBuffer(xMin, xMax, numIncrements, xValBuffer4, 145 yValBuffer4, yExtrema, currentRatPoly); 146 147 if (yExtrema[0] < yMin) { 148 yMin = yExtrema[0]; 149 } 150 151 if (yExtrema[1] > yMax) { 152 yMax = yExtrema[1]; 153 } 154 } 155 156 // At this point, min and max have been computed, and buffers 157 // are full. Draw axes, then draw graph line. 158 int bord = 32; 159 g.setColor(Color.black); 160 g.drawLine(bord, h - bord, w - bord, h - bord); // horizontal axis 161 g.drawLine(bord, bord, bord, h - bord); // vertical axis 162 163 float gw = w - (2 * bord); // width of graph area inside axes 164 float gh = h - (2 * bord); // height of graph area inside axes 165 166 // Draw axis labels. 167 msg = Float.toString(xMin); 168 g.drawString(msg, bord, h - 8); 169 170 msg = Float.toString(xMax); 171 g.drawString(msg, w - bord, h - 8); 172 173 msg = Float.toString(yMin); 174 g.drawString(msg, 8, h - bord); 175 176 msg = Float.toString(yMax); 177 g.drawString(msg, 8, bord); 178 179 // Draw graph line. 180 g.setColor(Color.red); 181 drawPlot(xMin, xMax, yMin, yMax, xValBuffer1, yValBuffer1, gw, gh, 182 bord, numIncrements, h, g); 183 184 g.setColor(Color.blue); 185 if (calcFrame.stack.size() > 1) { 186 assert xValBuffer2 != null 187 : "@SuppressWarnings(nullness): dependent: non-null if calcFrame.stack.size() > 1"; 188 assert yValBuffer2 != null 189 : "@SuppressWarnings(nullness): dependent: non-null if calcFrame.stack.size() > 1"; 190 drawPlot(xMin, xMax, yMin, yMax, xValBuffer2, yValBuffer2, gw, gh, 191 bord, numIncrements, h, g); 192 } 193 194 g.setColor(Color.green); 195 if (calcFrame.stack.size() > 2) { 196 assert xValBuffer3 != null 197 : "@SuppressWarnings(nullness): dependent: non-null if calcFrame.stack.size() > 2"; 198 assert yValBuffer3 != null 199 : "@SuppressWarnings(nullness): dependent: non-null if calcFrame.stack.size() > 2"; 200 drawPlot(xMin, xMax, yMin, yMax, xValBuffer3, yValBuffer3, gw, gh, 201 bord, numIncrements, h, g); 202 } 203 204 g.setColor(Color.orange); 205 if (calcFrame.stack.size() > 3) { 206 assert xValBuffer4 != null 207 : "@SuppressWarnings(nullness): dependent: non-null if calcFrame.stack.size() > 3"; 208 assert yValBuffer4 != null 209 : "@SuppressWarnings(nullness): dependent: non-null if calcFrame.stack.size() > 3"; 210 drawPlot(xMin, xMax, yMin, yMax, xValBuffer4, yValBuffer4, gw, gh, 211 bord, numIncrements, h, g); 212 } 213 214 // Consider abstracting this better! 215 } 216 217 public void updatePlotBuffer(float xMin, float xMax, int numIncrements, 218 float xValBuffer[], float yValBuffer[], float yExtrema[], 219 RatPoly currentRatPoly) { 220 float delta = (xMax - xMin) / numIncrements; 221 float currentX = xMin; 222 boolean firstTime = true; 223 int i; 224 float yVal = 0; 225 float yMin = 0; 226 float yMax = 0; 227 228 for (i = 0; i < numIncrements; ++i) { 229 if (currentX < xMax) { 230 xValBuffer[i] = currentX; 231 yVal = (float) currentRatPoly.eval(currentX); 232 yValBuffer[i] = yVal; 233 234 if (firstTime) { 235 firstTime = false; 236 yMin = yVal; 237 yMax = yVal; 238 } else { 239 if (yVal < yMin) { 240 yMin = yVal; 241 } 242 243 if (yVal > yMax) { 244 yMax = yVal; 245 } 246 } 247 248 currentX += delta; 249 } else { 250 xValBuffer[i] = xValBuffer[i - 1]; 251 yValBuffer[i] = yValBuffer[i - 1]; 252 } 253 } 254 255 yExtrema[0] = yMin; 256 yExtrema[1] = yMax; 257 } 258 259 public void drawPlot(float xMin, float xMax, float yMin, float yMax, 260 float xValBuffer[], float yValBuffer[], float gw, float gh, 261 int bord, int numIncrements, int h, Graphics g) { 262 float xVal = 0; 263 float yVal = 0; 264 float previousX = 0; 265 float previousY = 0; 266 boolean firstTime = true; 267 float xRange = xMax - xMin; 268 float yRange = yMax - yMin; 269 int xPrevScaled = 0; 270 int yPrevScaled = 0; 271 int xScaled = 0; 272 int yScaled = 0; 273 int i; 274 for (i = 0; i < numIncrements; ++i) { 275 if (firstTime) { 276 firstTime = false; 277 xVal = xValBuffer[i]; 278 yVal = yValBuffer[i]; 279 previousX = xVal; 280 previousY = yVal; 281 } else { 282 previousX = xVal; 283 previousY = yVal; 284 xVal = xValBuffer[i]; 285 yVal = yValBuffer[i]; 286 } 287 288 // Now draw a line from previous to current. 289 xPrevScaled = Math.round(((previousX - xMin) * gw) / xRange); 290 yPrevScaled = Math.round(((previousY - yMin) * gh) / yRange); 291 xScaled = Math.round(((xVal - xMin) * gw) / xRange); 292 yScaled = Math.round(((yVal - yMin) * gh) / yRange); 293 294 g.drawLine(bord + xPrevScaled, h - bord - yPrevScaled, bord 295 + xScaled, h - bord - yScaled); 296 } 297 } 298 299}