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