Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
3653 | schaersvoo | 1 | /* jm.evers 10/2009 |
2 | |||
3 | This is just a copy of Parametric.java ; added a param "showAll" |
||
4 | <param name="showAll" value="0/no"> will show the graph and no input controls |
||
5 | Any other values will revert to Parametric.java behaviour. |
||
6 | |||
7 | The evalues used to generate the parametric figure are however |
||
8 | still easy to be read by pupils looking at the page source... |
||
9 | |||
10 | example: |
||
11 | <html> |
||
12 | <body> |
||
13 | <applet archive="./jcm.jar" code="SilentParametric.class" width="640" height="360"> |
||
14 | <param name="showAll" value="no"><!-- yes will give user inputs --> |
||
15 | <param name="FrameTitle" value="Parametric Curves"> |
||
16 | <param name="UseGrid" value="yes"> |
||
17 | <param name="Limits" value="-1.5,1.5,-1.5,1.5"> |
||
18 | <param name="UseMouseZoom" value="no"> |
||
19 | <param name="UsePanner" value="no"> |
||
20 | <param name="UseFunctionInput" value="no"> |
||
21 | <param name="UseParamInputs" value="no"> |
||
22 | <param name="UseRestoreButton" value="yes"> |
||
23 | <param name="UseEqualizeButton" value="yes"> |
||
24 | <param name="SetLimitsButton" value="yes"> |
||
25 | <param name="UseZoomButtons" value="yes"> |
||
26 | |||
27 | <param name="LoopStyle" value="2"><!-- 0,1,2 0=once,1=restart,2=back and forth--> |
||
28 | <param name="File" value="http://localhost/test.data"> |
||
29 | <!-- |
||
30 | or define functions through params: |
||
31 | <param name="Function" value="sin(1/2*t)"> |
||
32 | <param name="Function2" value="sin(2*t)"> |
||
33 | --> |
||
34 | <param name="FunctionLabel" value="x(t)"> |
||
35 | <param name="FunctionLabel2" value="y(t)"> |
||
36 | <param name="TracerIntervals" value="150"> |
||
37 | <param name="ParameterMin" value="0"> |
||
38 | <param name="ParameterMax" value="2*pi/(1/2)"> |
||
39 | <param name="PanelBackground" value="255 235 245"> |
||
40 | <param name="UseComputeButton" value="no"> |
||
41 | <param name="TwoLimitsColumns" value="no"> |
||
42 | <param name="UseLimitsPanel" value="no"> |
||
43 | <param namr="Insets" value="no"> |
||
44 | <param name="BackgroundColor" value="255 235 245"> |
||
45 | </applet> |
||
46 | </body> |
||
47 | </html> |
||
48 | */ |
||
49 | |||
50 | /************************************************************************* |
||
51 | * * |
||
52 | * This source code file, and compiled classes derived from it, can * |
||
53 | * be used and distributed without restriction, including for commercial * |
||
54 | * use. (Attribution is not required but is appreciated.) * |
||
55 | * * |
||
56 | * David J. Eck * |
||
57 | * Department of Mathematics and Computer Science * |
||
58 | * Hobart and William Smith Colleges * |
||
59 | * Geneva, New York 14456, USA * |
||
60 | * Email: eck@hws.edu WWW: http://math.hws.edu/eck/ * |
||
61 | * * |
||
62 | *************************************************************************/ |
||
63 | |||
64 | |||
65 | // The ParametricCurve applet is a configurable applet that displays a parametric |
||
66 | // curve defined by two functions of a parameter t. There can be a "Tracer" button |
||
67 | // on the applet. When the user clicks this button, a crosshair is moved along |
||
68 | // the curve from beginning to end. |
||
69 | |||
70 | import java.awt.*; |
||
71 | import java.applet.Applet; |
||
72 | import java.util.StringTokenizer; |
||
73 | import java.util.Hashtable; |
||
74 | import edu.hws.jcm.draw.*; |
||
75 | import edu.hws.jcm.data.*; |
||
76 | import edu.hws.jcm.functions.*; |
||
77 | import edu.hws.jcm.awt.*; |
||
78 | import java.net.*; |
||
79 | import java.io.*; |
||
80 | |||
81 | |||
82 | public class SilentParametric extends GenericGraphApplet { |
||
83 | |||
84 | // Declare some private variables that are created in one method in |
||
85 | // this class and used in a second method. |
||
86 | |||
87 | private Function xFunc,yFunc; // The functions that are graphed. |
||
88 | private ParametricCurve graph; // The graph of the function. |
||
89 | private Animator tracer; // for tracing the curve by moving a crosshair along it |
||
90 | private Crosshair crosshair; // Crosshair used for tracing the graph |
||
91 | private VariableInput tMin,tMax; // for inputting limits on t |
||
92 | private VariableInput tIntervals; // for inutting the number of intervals into which the t-range is divided |
||
93 | private ExpressionInput functionInput2; // for inputting yFunc; xFunc is input in functionInput |
||
94 | public String tMaxString="2"; |
||
95 | public String tMinString="-2"; |
||
96 | |||
97 | protected void setUpParameterDefaults() { |
||
98 | parameterDefaults = new Hashtable(); |
||
99 | parameterDefaults.put("TwoLimitsColumns", "yes"); |
||
100 | parameterDefaults.put("Variable","t"); |
||
101 | parameterDefaults.put("XName","x"); // we need this so that xmin and xmax boxes are labeled correctly; |
||
102 | // without it, the name would come from the variable name, t, instead of x |
||
103 | parameterDefaults.put("FunctionLabel", " " + getParameter("XName") + "(" + getParameter("Variable") + ") = "); |
||
104 | parameterDefaults.put("FunctionLabel2", " " + getParameter("YName","y") + "(" + getParameter("Variable") + ") = "); |
||
105 | } |
||
106 | |||
107 | protected void setUpCanvas() { // Override this to add more stuff to the canvas. |
||
108 | |||
109 | super.setUpCanvas(); // Do the common setup: Add the axes and |
||
110 | |||
111 | // When setUpCanvas is called, the function inputs already exist, if they are |
||
112 | // to be used, since they are created in setUpBopttomPanel(), which is called |
||
113 | // before setUpCanvas(). If functionInput exists, add a graph of the functions |
||
114 | // from functionInput and functionInput2 to the canvas. If not, create a graph |
||
115 | // of the functions specified by the parameters named "Function" and "Function2". |
||
116 | |||
117 | if (functionInput != null) { |
||
118 | xFunc = functionInput.getFunction(xVar); |
||
119 | yFunc = functionInput2.getFunction(xVar); |
||
120 | } |
||
121 | else { |
||
122 | String xFuncDef = " cos(" + xVar.getName() + ") + cos(3*" + xVar.getName() + ")"; |
||
123 | String yFuncDef = " sin(4*" + xVar.getName() + ") - sin(2*" + xVar.getName() + ")"; |
||
124 | String file = getParameter("File"); |
||
125 | // jm.evers begin |
||
126 | if(file != null){ |
||
127 | //System.out.println("fetching data from "+file); |
||
128 | String newdata=""; |
||
129 | try{ newdata = load(file); |
||
130 | // scheme: function1,function2,min,max |
||
131 | StringTokenizer t = new StringTokenizer(newdata, ","); |
||
132 | if(t.countTokens() != 4) {System.out.println("scheme is: function1,function2,min,max");} |
||
133 | else { |
||
134 | xFuncDef = t.nextToken(); |
||
135 | yFuncDef = t.nextToken(); |
||
136 | tMinString = t.nextToken(); |
||
137 | tMaxString = t.nextToken(); |
||
138 | } |
||
139 | } catch(Exception e){System.out.println("Could not read data from "+file);} |
||
140 | } |
||
141 | else |
||
142 | { |
||
143 | xFuncDef = getParameter("Function", xFuncDef); |
||
144 | yFuncDef = getParameter("Function2", yFuncDef); |
||
145 | } |
||
146 | // jm.evers end |
||
147 | Function f = new SimpleFunction( parser.parse(xFuncDef), xVar ); |
||
148 | xFunc = new WrapperFunction(f); |
||
149 | f = new SimpleFunction( parser.parse(yFuncDef), xVar ); |
||
150 | yFunc = new WrapperFunction(f); |
||
151 | } |
||
152 | graph = new ParametricCurve(xFunc,yFunc); |
||
153 | Color color = getColorParam("CurveColor"); |
||
154 | if (color != null) |
||
155 | graph.setColor(color); |
||
156 | |||
157 | // if inputs are desired to control the parameter on the curve, set them up here |
||
158 | |||
159 | if ("no".equalsIgnoreCase(getParameter("UseParamInputs","yes"))) { |
||
160 | tMin = new VariableInput(xVar.getName() + "Start",tMinString); |
||
161 | tMax = new VariableInput(xVar.getName() + "End",tMaxString); |
||
162 | tIntervals = new VariableInput("Intervals", getParameter("Intervals","500")); |
||
163 | tIntervals.setInputStyle(VariableInput.INTEGER); |
||
164 | tIntervals.setMin(1); |
||
165 | tIntervals.setMax(5000); |
||
166 | tMin.setOnUserAction(mainController); |
||
167 | tMax.setOnUserAction(mainController); |
||
168 | tIntervals.setOnUserAction(mainController); |
||
169 | graph.setTMin(tMin); |
||
170 | graph.setTMax(tMax); |
||
171 | graph.setIntervals(tIntervals); |
||
172 | // jm.evers begin |
||
173 | String s = getParameter("showAll"); |
||
174 | boolean showAll=true; |
||
175 | if(s.equalsIgnoreCase("no") || s.equalsIgnoreCase("0")){showAll=false;} |
||
176 | // jm.evers end |
||
177 | if(showAll){ |
||
178 | if (limitsPanel != null) { |
||
179 | // componets will be added to limitsPanel in setUpLimitsPanel() |
||
180 | mainController.add(tMin); // This is not done automatically, since they are in a limits panel |
||
181 | mainController.add(tMax); |
||
182 | mainController.add(tIntervals); |
||
183 | } |
||
184 | else { |
||
185 | JCMPanel ap = new JCMPanel(9,0); |
||
186 | ap.setBackground(getColorParam("PanelBackground", Color.lightGray)); |
||
187 | ap.add(new Label(tMin.getName())); |
||
188 | ap.add(tMin); |
||
189 | ap.add(new Label()); |
||
190 | ap.add(new Label(tMax.getName())); |
||
191 | ap.add(tMax); |
||
192 | ap.add(new Label()); |
||
193 | ap.add(new Label(tIntervals.getName())); |
||
194 | ap.add(tIntervals); |
||
195 | ap.add(new Label()); |
||
196 | mainPanel.add(ap,BorderLayout.EAST); |
||
197 | } |
||
198 | } |
||
199 | } |
||
200 | else { |
||
201 | try { |
||
202 | graph.setTMin( new Constant((new Double(tMinString)).doubleValue()) ); |
||
203 | graph.setTMax( new Constant((new Double(tMaxString)).doubleValue()) ); |
||
204 | graph.setIntervals( new Constant((new Double(getParameter("Intervals","500"))).doubleValue()) ); |
||
205 | } |
||
206 | catch (NumberFormatException e) { |
||
207 | } |
||
208 | } |
||
209 | |||
210 | // If the applet is configured to have a tracer button, create it and add the crosshair to the canvas |
||
211 | |||
212 | if (! "no".equalsIgnoreCase( getParameter("UseTracer","yes") ) ) { |
||
213 | tracer = new Animator(); |
||
214 | String loopstyle=getParameter("LoopStyle"); |
||
215 | if(loopstyle != null){ |
||
216 | if(loopstyle.equals("0")){tracer.setLoopStyle(0);} |
||
217 | else |
||
218 | if(loopstyle.equals("1")){tracer.setLoopStyle(1);} |
||
219 | else |
||
220 | if(loopstyle.equals("2")){tracer.setLoopStyle(2);} |
||
221 | else |
||
222 | tracer.setLoopStyle(2); |
||
223 | } |
||
224 | tracer.setMin(graph.getTMin()); |
||
225 | tracer.setMax(graph.getTMax()); |
||
226 | tracer.setUndefinedWhenNotRunning(true); |
||
227 | tracer.setStartButtonName("Trace Curve!"); |
||
228 | double[] d = getNumericParam("TracerIntervals"); |
||
229 | int ints; |
||
230 | if (d == null || d.length != 1) |
||
231 | ints = 100; |
||
232 | else |
||
233 | ints = (int)Math.round(d[0]); |
||
234 | if (ints <= 0) |
||
235 | tracer.setIntervals(graph.getIntervals()); |
||
236 | else |
||
237 | tracer.setIntervals(ints); |
||
238 | Variable v = tracer.getValueAsVariable(); |
||
239 | crosshair = new Crosshair( new ValueMath(xFunc,v), new ValueMath(yFunc,v) ); |
||
240 | crosshair.setLineWidth(3); |
||
241 | crosshair.setColor(getColorParam("CrosshairColor",Color.gray)); |
||
242 | canvas.add(crosshair); |
||
243 | |||
244 | if (inputPanel != null) { |
||
245 | inputPanel.add(tracer,BorderLayout.WEST); |
||
246 | } |
||
247 | else if (limitsPanel == null) { |
||
248 | Panel p = new Panel(); |
||
249 | p.add(tracer); |
||
250 | mainPanel.add(p,BorderLayout.SOUTH); |
||
251 | } |
||
252 | // if inputPanel is null but limitsPanel is not null, the tracer will be |
||
253 | // added to the limit control panel in setUpLimitsPanel() |
||
254 | } |
||
255 | |||
256 | canvas.add(graph); // Finally, add the graph to the canvas. |
||
257 | |||
258 | } // end setUpCanvas() |
||
259 | |||
260 | |||
261 | protected void setUpLimitsPanel() { |
||
262 | super.setUpLimitsPanel(); |
||
263 | if (limitsPanel != null && tMin != null) { // add parameter inputs to limits panel |
||
264 | limitsPanel.addComponentPair(tMin,tMax); |
||
265 | limitsPanel.addComponent(tIntervals); |
||
266 | } |
||
267 | if (inputPanel == null && tracer != null && limitsPanel != null) { |
||
268 | limitsPanel.addComponent(tracer); |
||
269 | } |
||
270 | } |
||
271 | |||
272 | |||
273 | protected void setUpBottomPanel() { // override this to make a panel containing inputs for two functions |
||
274 | if ( ! "no".equalsIgnoreCase(getParameter("UseFunctionInput", "yes")) ) { |
||
275 | |||
276 | inputPanel = new JCMPanel(); |
||
277 | inputPanel.setBackground( getColorParam("PanelBackground", Color.lightGray) ); |
||
278 | Panel in = new JCMPanel(2,1); |
||
279 | inputPanel.add(in,BorderLayout.CENTER); |
||
280 | |||
281 | if ( ! "no".equalsIgnoreCase(getParameter("UseComputeButton", "yes")) ) { |
||
282 | String cname = getParameter("ComputeButtonName", "New Functions"); |
||
283 | computeButton = new Button(cname); |
||
284 | inputPanel.add(computeButton, BorderLayout.EAST); |
||
285 | computeButton.addActionListener(this); |
||
286 | } |
||
287 | |||
288 | String varName = getParameter("Variable"); |
||
289 | String def = getParameter("Function"); |
||
290 | if (def == null) |
||
291 | def = "cos(" + varName + ") + cos(3*" + varName + ")"; |
||
292 | functionInput = new ExpressionInput(def,parser); |
||
293 | String label = getParameter("FunctionLabel"); |
||
294 | if ("none".equalsIgnoreCase(label)) |
||
295 | in.add(functionInput); |
||
296 | else { |
||
297 | Panel p = new JCMPanel(); |
||
298 | p.add(functionInput,BorderLayout.CENTER); |
||
299 | p.add( new Label(label), BorderLayout.WEST ); |
||
300 | in.add(p); |
||
301 | } |
||
302 | |||
303 | def = getParameter("Function2"); |
||
304 | if (def == null) |
||
305 | def = "sin(4*" + varName + ") - sin(2*" + varName + ")"; |
||
306 | functionInput2 = new ExpressionInput(def,parser); |
||
307 | label = getParameter("FunctionLabel2"); |
||
308 | if ("none".equalsIgnoreCase(label)) |
||
309 | in.add(functionInput2); |
||
310 | else { |
||
311 | Panel p = new JCMPanel(); |
||
312 | p.add(functionInput2,BorderLayout.CENTER); |
||
313 | p.add( new Label(label), BorderLayout.WEST ); |
||
314 | in.add(p); |
||
315 | } |
||
316 | |||
317 | mainPanel.add(inputPanel, BorderLayout.SOUTH); |
||
318 | functionInput.setOnUserAction(mainController); |
||
319 | functionInput2.setOnUserAction(mainController); |
||
320 | } |
||
321 | } |
||
322 | |||
323 | |||
324 | protected void setUpMainPanel() { // Override to set up controller for tracer, if there is one |
||
325 | |||
326 | super.setUpMainPanel(); // Do the common setup |
||
327 | |||
328 | if ( tracer == null ) { |
||
329 | return; // If the applet is not configured to use a trace button, there is nothing to do. |
||
330 | } |
||
331 | |||
332 | Controller traceController = new Controller(); // A controler that will only recompute the crosshair position |
||
333 | traceController.add(tracer); |
||
334 | traceController.add(crosshair); |
||
335 | tracer.setOnChange(traceController); |
||
336 | |||
337 | } // end setUpMainPanel() |
||
338 | |||
339 | protected void doLoadExample(String example) { |
||
340 | // This method is called when the user loads an example from the |
||
341 | // example menu (if there is one). It overrides an empty method |
||
342 | // in GenericGraphApplet. |
||
343 | // For the Parametric applet, the example string should contain |
||
344 | // two expression that defines the curve to be graphed, separated |
||
345 | // by a semicolon. This can optionally |
||
346 | // be followed by another semicolon and a list of four to seven numbers. |
||
347 | // The first four numbers give the x- and y-limits to be used for the |
||
348 | // example. If they are not present, then -5,5,-5,5 is used. The |
||
349 | // next three numbers specify the minimum value for the parameter, the |
||
350 | // maximum value, and the number of intervals into which the range of |
||
351 | // parameter values is divided. |
||
352 | |||
353 | if (tracer != null) |
||
354 | tracer.stop(); |
||
355 | |||
356 | int pos = example.indexOf(";"); |
||
357 | if (pos == -1) |
||
358 | return; // illegal example -- must have two functions |
||
359 | String example2 = example.substring(pos+1); |
||
360 | example = example.substring(0,pos); |
||
361 | pos = example2.indexOf(";"); |
||
362 | |||
363 | |||
364 | double[] limits = { -5,5,-5,5 }; // x- and y-limits to use |
||
365 | |||
366 | if (pos > 0) { |
||
367 | // Get limits from example2 text. |
||
368 | String nums = example2.substring(pos+1); |
||
369 | example2 = example2.substring(0,pos); |
||
370 | StringTokenizer toks = new StringTokenizer(nums, " ,"); |
||
371 | if (toks.countTokens() >= 4) { |
||
372 | for (int i = 0; i < 4; i++) { |
||
373 | try { |
||
374 | Double d = new Double(toks.nextToken()); |
||
375 | limits[i] = d.doubleValue(); |
||
376 | } |
||
377 | catch (NumberFormatException e) { |
||
378 | } |
||
379 | } |
||
380 | } |
||
381 | if (toks.hasMoreTokens()) { |
||
382 | try { |
||
383 | double d = (new Double(toks.nextToken())).doubleValue(); |
||
384 | if (tMin == null) { |
||
385 | graph.setTMin(new Constant(d)); |
||
386 | if (tracer != null) |
||
387 | tracer.setMin(d); |
||
388 | } |
||
389 | else |
||
390 | tMin.setVal(d); |
||
391 | } |
||
392 | catch (NumberFormatException e) { |
||
393 | } |
||
394 | } |
||
395 | if (toks.hasMoreTokens()) { |
||
396 | try { |
||
397 | double d = (new Double(toks.nextToken())).doubleValue(); |
||
398 | if (tMax == null) { |
||
399 | graph.setTMax(new Constant(d)); |
||
400 | if (tracer != null) |
||
401 | tracer.setMax(d); |
||
402 | } |
||
403 | else |
||
404 | tMax.setVal(d); |
||
405 | } |
||
406 | catch (NumberFormatException e) { |
||
407 | } |
||
408 | } |
||
409 | if (toks.hasMoreTokens()) { |
||
410 | try { |
||
411 | int d = (int)Math.round((new Double(toks.nextToken())).doubleValue()); |
||
412 | if (tIntervals == null) { |
||
413 | if (tracer != null && tracer.getIntervals() == graph.getIntervals()) |
||
414 | tracer.setIntervals(d); |
||
415 | graph.setIntervals(new Constant(d)); |
||
416 | } |
||
417 | else |
||
418 | tIntervals.setVal(d); |
||
419 | } |
||
420 | catch (NumberFormatException e) { |
||
421 | } |
||
422 | } |
||
423 | } |
||
424 | |||
425 | // Set up the example data and recompute everything. |
||
426 | |||
427 | if (functionInput != null) { |
||
428 | // If there is a function input box, put the example text in it. |
||
429 | functionInput.setText(example); |
||
430 | functionInput2.setText(example2); |
||
431 | } |
||
432 | else { |
||
433 | // If there is no user input, set the function in the graph directly. |
||
434 | try { |
||
435 | Function f = new SimpleFunction( parser.parse(example), xVar ); |
||
436 | ((WrapperFunction)xFunc).setFunction(f); |
||
437 | Function g = new SimpleFunction( parser.parse(example2), xVar ); |
||
438 | ((WrapperFunction)yFunc).setFunction(g); |
||
439 | } |
||
440 | catch (ParseError e) { |
||
441 | // There should't be parse error's in the Web-page |
||
442 | // author's examples! If there are, the function |
||
443 | // just won't change. |
||
444 | } |
||
445 | } |
||
446 | CoordinateRect coords = canvas.getCoordinateRect(0); |
||
447 | coords.setLimits(limits); |
||
448 | coords.setRestoreBuffer(); |
||
449 | mainController.compute(); |
||
450 | |||
451 | } // end doLoadExample() |
||
452 | |||
453 | |||
454 | public void stop() { // stop animator when applet is stopped |
||
455 | if (tracer != null) |
||
456 | tracer.stop(); |
||
457 | super.stop(); |
||
458 | } |
||
459 | |||
460 | |||
461 | // jm.evers; handy functions, not invented here :( |
||
462 | public static byte [] loadURL(URL url) throws IOException { |
||
463 | int bufSize = 1024 * 2; |
||
464 | byte [] buf = new byte[bufSize]; |
||
465 | ByteArrayOutputStream bout = new ByteArrayOutputStream(); |
||
466 | BufferedInputStream in = new BufferedInputStream(url.openStream()); |
||
467 | int n; |
||
468 | while ((n = in.read(buf)) > 0){ |
||
469 | bout.write(buf, 0, n); |
||
470 | } |
||
471 | try { in.close(); } catch (Exception ignored) { } |
||
472 | return bout.toByteArray(); |
||
473 | } |
||
474 | |||
475 | public static String loadFile(String fname) throws IOException { |
||
476 | byte[] bytes = loadURL(new URL("file:" + fname)); |
||
477 | return new String(bytes); |
||
478 | } |
||
479 | |||
480 | public static String load(String fileOrURL) throws IOException { |
||
481 | try { |
||
482 | URL url = new URL(fileOrURL); |
||
483 | return new String(loadURL(url));} |
||
484 | catch (Exception e) { return loadFile(fileOrURL);} |
||
485 | } |
||
486 | } |
||
487 | // end class Parametric |