Source Code Cross Referenced for ParametricCurve.java in  » Science » jcm1-source » edu » hws » jcm » draw » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Science » jcm1 source » edu.hws.jcm.draw 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*************************************************************************
002:         *                                                                        *
003:         *   1) This source code file, in unmodified form, and compiled classes   *
004:         *      derived from it can be used and distributed without restriction,  *
005:         *      including for commercial use.  (Attribution is not required       *
006:         *      but is appreciated.)                                              *
007:         *                                                                        *
008:         *    2) Modified versions of this file can be made and distributed       *
009:         *       provided:  the modified versions are put into a Java package     *
010:         *       different from the original package, edu.hws;  modified          *
011:         *       versions are distributed under the same terms as the original;   *
012:         *       and the modifications are documented in comments.  (Modification *
013:         *       here does not include simply making subclasses that belong to    *
014:         *       a package other than edu.hws, which can be done without any      *
015:         *       restriction.)                                                    *
016:         *                                                                        *
017:         *   David J. Eck                                                         *
018:         *   Department of Mathematics and Computer Science                       *
019:         *   Hobart and William Smith Colleges                                    *
020:         *   Geneva, New York 14456,   USA                                        *
021:         *   Email: eck@hws.edu          WWW: http://math.hws.edu/eck/            *
022:         *                                                                        *
023:         *************************************************************************/package edu.hws.jcm.draw;
024:
025:        import edu.hws.jcm.data.*;
026:        import edu.hws.jcm.awt.*;
027:        import java.awt.*;
028:        import java.util.Vector;
029:
030:        /**
031:         * A ParametricCurve is defined by two functions, x(t) and y(t) of a variable, t,
032:         * for t in a specified interval.  The curve is simply defined as a sequence of line
033:         * segments connecting points of the form (x(t),y(t)), except where one of the functions
034:         * is undefined.  Also, in some cases a
035:         * discontinuity will be detected and no line will be drawn between two of the points.
036:         */
037:
038:        public class ParametricCurve extends Drawable implements  Computable {
039:
040:            private Function xFunc, yFunc; //The functions of t that are graphed.
041:
042:            private Color graphColor = Color.magenta; //Color of the graph.
043:
044:            private boolean changed; // Used internally to indicate that data has to be recomputed.
045:
046:            private transient int[] xcoord, ycoord; //points on graph; xcoord[i] == Integer.MIN_VALUE
047:            //for points where a gap occurs.
048:
049:            private Value tmin, tmax; // Value objects giving the minimum and maximum value of t.
050:
051:            private Value intervals; // Value object giving the number of intervals into which the
052:            // interval (tmin,tmax) is to be divided.
053:
054:            private double tmin_val, tmax_val; // The values of tmin and tmax.
055:            // (tmin_val is set to Double.NaN if any of the values are bad, and nothing is drawn.)
056:            private int intervals_val; // The value of intervals.
057:
058:            /**
059:             * Create a ParametricCurve with nothing to graph.  The functions and other values
060:             * can be set later.
061:             */
062:            public ParametricCurve() {
063:                this (null, null, null, null, null);
064:            }
065:
066:            /**
067:             * Create a parametric curve with x and y coordinates given by the specified functions
068:             * of the parameter t.  Defaults values are used for tmin, tmax, and the number of intervals.
069:             * If either function is null, nothing is drawn.
070:             */
071:            public ParametricCurve(Function xFunc, Function yFunc) {
072:                this (xFunc, yFunc, null, null, null);
073:            }
074:
075:            /**
076:             * Create a parametric curve with the specified values.
077:             *
078:             * @param xFunc A Function of one variable giving the x-coordinate of points on the curve.  If this
079:             *              is null, then nothing will be drawn.
080:             * @param yFunc A Function of one variable giving the y-coordinate of points on the curve.  If this
081:             *              is null, then nothing will be drawn.
082:             * @param tmin A Value object giving one endpoint of the domain of the parameter.  If this is null,
083:             *             the default value -5 is used.
084:             * @param tmax A Value object giving the second endpoint of the domain of the parameter.  If this is null,
085:             *             the default value 5 is used.  Note that it is not required that tmax be greater than tmin.
086:             * @param intervals A Value object giving the number of intervals into which the domain is subdivided.
087:             *             If this is null, the default value 200 is used.  The number of points on the curve will be
088:             *             the number of intervals plus one (unless a function is undefined at some value of the parameter
089:             *             or if a discontinuity is detected).  The number of intervals is clamped to the range 1 to 10000.
090:             *             Values outside this range would certainly be unreasonable.
091:             */
092:            public ParametricCurve(Function xFunc, Function yFunc, Value tmin,
093:                    Value tmax, Value intevals) {
094:                if ((xFunc != null && xFunc.getArity() != 1)
095:                        || (yFunc != null && yFunc.getArity() != 1))
096:                    throw new IllegalArgumentException(
097:                            "Internal Error:  The functions that define a parametric curve must be functions of one variable.");
098:                this .xFunc = xFunc;
099:                this .yFunc = yFunc;
100:                this .tmin = tmin;
101:                this .tmax = tmax;
102:                this .intervals = intervals;
103:                changed = true;
104:            }
105:
106:            /**
107:             * Set the color to be used for drawing the graph.
108:             */
109:            public void setColor(Color c) {
110:                if (c != null & !c.equals(graphColor)) {
111:                    graphColor = c;
112:                    needsRedraw();
113:                }
114:            }
115:
116:            /**
117:             * Get the color that is used to draw the graph.
118:             */
119:            public Color getColor() {
120:                return graphColor;
121:            }
122:
123:            /**
124:             * Sets the functions that gives the coordinates of the curve to be graphed.  If either function is
125:             * null, then nothing is drawn.  If non-null, each function must be a function of one variable.
126:             */
127:            synchronized public void setFunctions(Function x, Function y) {
128:                setXFunction(x);
129:                setYFunction(y);
130:            }
131:
132:            /**
133:             * Set the function that gives the x-coordinate of the curve to be graphed.  If this is
134:             * null, then nothing is drawn.  If non-null, it must be a function of one variable.
135:             */
136:            synchronized public void setXFunction(Function x) {
137:                if (x != null && x.getArity() != 1)
138:                    throw new IllegalArgumentException(
139:                            "Internal Error:  ParametricCurve can only graph functions of one variable.");
140:                if (x != xFunc) {
141:                    xFunc = x;
142:                    changed = true;
143:                    needsRedraw();
144:                }
145:            }
146:
147:            /**
148:             * Set the function that gives the y-coordinate of the curve to be graphed.  If this is
149:             * null, then nothing is drawn.  If non-null, it must be a function of one variable.
150:             */
151:            synchronized public void setYFunction(Function y) {
152:                if (y != null && y.getArity() != 1)
153:                    throw new IllegalArgumentException(
154:                            "Internal Error:  ParametricCurve can only graph functions of one variable.");
155:                if (y != yFunc) {
156:                    yFunc = y;
157:                    changed = true;
158:                    needsRedraw();
159:                }
160:            }
161:
162:            /**
163:             *  Get the (possibly null) function that gives the x-coordinate of the curve.
164:             */
165:            public Function getXFunction() {
166:                return xFunc;
167:            }
168:
169:            /**
170:             *  Get the (possibly null) function that gives the y-coordinate of the curve.
171:             */
172:            public Function getYFunction() {
173:                return yFunc;
174:            }
175:
176:            /**
177:             * Specify the number of subintervals into which the domain of the parametric curve is divided.
178:             * The interval (tmin,tmax) is divided into subintervals.  X and y coordinates of the parametric curve
179:             * are computed at each endpoint of these subintervals, and then the points are connected by lines.
180:             * If the parameter of this function is null, or if no interval count is ever specified, then a 
181:             * default value of 200 is used.
182:             */
183:            public void setIntervals(Value intervalCount) {
184:                intervals = intervalCount;
185:                changed = true;
186:            }
187:
188:            /**
189:             *  Get the value object, possibly null, that determines the number of points on the curve.
190:             */
191:            public Value getIntervals() {
192:                return intervals;
193:            }
194:
195:            /** 
196:             * Set the Value objects that specify the domain of the paratmeter.
197:             */
198:            public void setLimits(Value tmin, Value tmax) {
199:                setTMin(tmin);
200:                setTMax(tmax);
201:            }
202:
203:            /**
204:             * Get the Value object, possibly null, that gives the left endpoint of the domain of the parameter.
205:             */
206:            public Value getTMin() {
207:                return tmin;
208:            }
209:
210:            /**
211:             * Get the Value object, possibly null, that gives the right endpoint of the domain of the parameter.
212:             */
213:            public Value getTMax() {
214:                return tmax;
215:            }
216:
217:            /**
218:             *  Set the Value object that gives the left endpoint of the domain of the parameter.  If this is null,
219:             *  then a default value of -5 is used for the left endpoint. (Note: actually, it's not required that
220:             *  tmin be less than tmax, so this might really be the "right" endpoint.)
221:             */
222:            public void setTMin(Value tmin) {
223:                this .tmin = tmin;
224:                changed = true;
225:            }
226:
227:            /**
228:             *  Set the Value object that gives the right endpoint of the domain of the parameter.  If this is null,
229:             *  then a default value of 5 is used for the right endpoint. (Note: actually, it's not required that
230:             *  tmin be less than tmax, so this might really be the "left" endpoint.)
231:             */
232:            public void setTMax(Value tmax) {
233:                this .tmax = tmax;
234:                changed = false;
235:            }
236:
237:            //------------------ Implementation details -----------------------------
238:
239:            /**
240:             * Recompute data for the graph and make sure that the area of the display canvas
241:             * that shows the graph is redrawn.  This method is ordinarily called by a
242:             * Controller.
243:             */
244:            synchronized public void compute() {
245:                setup();
246:                needsRedraw();
247:                changed = false;
248:            }
249:
250:            /**
251:             * Draw the graph (possibly recomputing the data if the CoordinateRect has changed).
252:             * This is not usually called directly.
253:             *
254:             */
255:            synchronized public void draw(Graphics g, boolean coordsChanged) {
256:                if (changed || coordsChanged || xcoord == null
257:                        || ycoord == null) {
258:                    setup();
259:                    changed = false;
260:                }
261:                if (xcoord == null || xcoord.length == 0)
262:                    return;
263:                g.setColor(graphColor);
264:                int x = xcoord[0];
265:                int y = ycoord[0];
266:                for (int i = 1; i < xcoord.length; i++) {
267:                    if (xcoord[i] == Integer.MIN_VALUE) {
268:                        do {
269:                            i++;
270:                        } while (i < xcoord.length
271:                                && xcoord[i] == Integer.MIN_VALUE);
272:                        if (i < xcoord.length) {
273:                            x = xcoord[i];
274:                            y = ycoord[i];
275:                        }
276:                    } else {
277:                        int x2 = xcoord[i];
278:                        int y2 = ycoord[i];
279:                        g.drawLine(x, y, x2, y2);
280:                        x = x2;
281:                        y = y2;
282:                    }
283:                }
284:            }
285:
286:            // ------------------------- Computing the points on the graph -----------------------
287:
288:            private double[] v = new double[1];
289:            private Cases case1x = new Cases();
290:            private Cases case2x = new Cases();
291:            private Cases case1y = new Cases();
292:            private Cases case2y = new Cases();
293:            private Cases case3x = new Cases();
294:            private Cases case3y = new Cases();
295:
296:            private Vector points = new Vector(250);
297:
298:            private Point eval(double t, Cases xcases, Cases ycases) {
299:                v[0] = t;
300:                if (xcases != null)
301:                    xcases.clear();
302:                if (ycases != null)
303:                    ycases.clear();
304:                double x = xFunc.getValueWithCases(v, xcases);
305:                double y = yFunc.getValueWithCases(v, ycases);
306:                if (Double.isNaN(x) || Double.isNaN(y))
307:                    return null;
308:                int xInt = coords.xToPixel(x);
309:                int yInt = coords.yToPixel(y);
310:                if (Math.abs(xInt) > 10000 || Math.abs(yInt) > 10000)
311:                    return null;
312:                return new Point(xInt, yInt);
313:            }
314:
315:            private void setup() {
316:                if (xFunc == null || yFunc == null || coords == null) {
317:                    xcoord = ycoord = new int[0]; // Nothing will be drawn
318:                    return;
319:                }
320:                double intervals_val_d;
321:                if (tmin == null)
322:                    tmin_val = -5;
323:                else
324:                    tmin_val = tmin.getVal();
325:                if (tmax == null)
326:                    tmax_val = 5;
327:                else
328:                    tmax_val = tmax.getVal();
329:                if (intervals == null)
330:                    intervals_val_d = 200;
331:                else
332:                    intervals_val_d = intervals.getVal();
333:                if (Double.isInfinite(tmin_val) || Double.isInfinite(tmax_val)
334:                        || Double.isInfinite(intervals_val_d)
335:                        || Double.isNaN(tmax_val)
336:                        || Double.isNaN(intervals_val_d))
337:                    tmin_val = Double.NaN; // Signal that data is bad, so nothing will be drawn.
338:                if (intervals_val_d < 1)
339:                    intervals_val = 1;
340:                else if (intervals_val > 10000)
341:                    intervals_val = 10000;
342:                else
343:                    intervals_val = (int) Math.round(intervals_val_d);
344:                if (Double.isNaN(tmin_val)) { // data is bad, don't draw
345:                    xcoord = ycoord = new int[0];
346:                    return;
347:                }
348:
349:                points.setSize(0);
350:
351:                double delta = (tmax_val - tmin_val) / intervals_val;
352:                double prevx, prevy, x, y, lastT;
353:                Point point, prevpoint;
354:
355:                double t = tmin_val;
356:                prevpoint = eval(t, case1x, case1y);
357:                if (prevpoint != null)
358:                    points.addElement(prevpoint);
359:
360:                for (int i = 1; i <= intervals_val; i++) {
361:                    t = tmin_val + i * delta;
362:                    point = eval(t, case2x, case2y);
363:                    if (point != null && prevpoint != null) {
364:                        if (!case1x.equals(case2x) || !case1y.equals(case2y))
365:                            // A discontinuity between two "onscreen" points.
366:                            discontinuity(prevpoint,
367:                                    tmin_val + (i - 1) * delta, point, t, 0);
368:                        else
369:                            points.addElement(point);
370:                    } else if (prevpoint == null && point != null) {
371:                        becomesDefined(prevpoint, tmin_val + (i - 1) * delta,
372:                                point, t, 0);
373:                    } else if (prevpoint != null && point == null) {
374:                        becomesUndefined(prevpoint, tmin_val + (i - 1) * delta,
375:                                point, t, 0);
376:                    }
377:
378:                    prevpoint = point;
379:                    Cases temp = case1x;
380:                    case1x = case2x;
381:                    case2x = temp;
382:                    temp = case1y;
383:                    case1y = case2y;
384:                    case2y = temp;
385:
386:                } // end for
387:
388:                xcoord = new int[points.size()];
389:                ycoord = new int[points.size()];
390:                for (int i = 0; i < ycoord.length; i++) {
391:                    Point p = (Point) points.elementAt(i);
392:                    xcoord[i] = p.x;
393:                    ycoord[i] = p.y;
394:                }
395:
396:            } // end setup();
397:
398:            private static int MAXDEPTH = 10; // maximum depth of recursion in the next three methods.
399:
400:            void discontinuity(Point p1, double t1, Point p2, double t2,
401:                    int depth) {
402:                // Both p1 and p2 are non-null; "cases" data at these two points does not agree;
403:                // Original point p1 (from case depth=1) is in points vector.  Case data for p1 and p2
404:                // is contained in case1x,case1y and case2x,case2y respectively.
405:                if (depth >= MAXDEPTH
406:                        || (Math.abs(p1.x - p2.x) < 2 && Math.abs(p1.y - p2.y) < 2)) {
407:                    if (points.elementAt(points.size() - 1) != p1)
408:                        points.addElement(p1);
409:                    if (depth >= MAXDEPTH)
410:                        points.addElement(new Point(Integer.MIN_VALUE, 0));
411:                    points.addElement(p2);
412:                    return;
413:                }
414:                double t = (t1 + t2) / 2;
415:                Point p = eval(t, case3x, case3y);
416:                if (p == null) {
417:                    becomesUndefined(p1, t1, p, t, depth + 1);
418:                    becomesDefined(p, t, p2, t2, depth + 1);
419:                } else if (case3x.equals(case1x) && case3y.equals(case1y)) {
420:                    discontinuity(p, t, p2, t2, depth + 1);
421:                } else if (case3x.equals(case2x) && case3y.equals(case2y)) {
422:                    discontinuity(p1, t1, p, t, depth + 1);
423:                } else {
424:                    discontinuity(p1, t1, p, t, depth + 2);
425:                    discontinuity(p, t, p2, t2, depth + 2);
426:                }
427:            }
428:
429:            void becomesUndefined(Point p1, double t1, Point p2, double t2,
430:                    int depth) {
431:                // p1 is non-null; p2 is null.  Original point p1 is in points vector.
432:                if (depth >= MAXDEPTH) {
433:                    if (points.elementAt(points.size() - 1) != p1)
434:                        points.addElement(p1);
435:                    points.addElement(new Point(Integer.MIN_VALUE, 0));
436:                    return;
437:                }
438:                double t = (t1 + t2) / 2;
439:                Point p = eval(t, null, null);
440:                if (p == null)
441:                    becomesUndefined(p1, t1, p, t, depth + 1);
442:                else
443:                    becomesUndefined(p, t, p2, t2, depth + 1);
444:            }
445:
446:            void becomesDefined(Point p1, double t1, Point p2, double t2,
447:                    int depth) {
448:                // p1 is null; p2 is non-null
449:                if (depth >= MAXDEPTH) {
450:                    if (points.size() > 0)
451:                        points.addElement(new Point(Integer.MIN_VALUE, 0));
452:                    points.addElement(p2);
453:                    return;
454:                }
455:                double t = (t1 + t2) / 2;
456:                Point p = eval(t, null, null);
457:                if (p != null)
458:                    becomesDefined(p1, t1, p, t, depth + 1);
459:                else
460:                    becomesDefined(p, t, p2, t2, depth + 1);
461:            }
462:
463:        } // end class ParametricCurve
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.