001 package ps1;
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 ps1. 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 }