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