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