Source Code Cross Referenced for CoordinateRect.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.awt.*;
026:        import edu.hws.jcm.data.Value;
027:        import java.awt.*;
028:        import java.util.Vector;
029:
030:        /**
031:         * A CoordinateRect represents a rectagular region in the xy-plane, specified
032:         * by values xmin,xmax,ymin,ymax.  The conditions ymin < ymax and xmin < xmax
033:         * are enforced.  (Values are swapped if necessary, and if min==max, they are
034:         * reset to -1 and +1.  If any of the values are set to an infinite or NaN
035:         * value, then the coordinate rect won't display anything except the message
036:         * "Error: undefined limits".)
037:         *   <P> When the Rect is mapped onto the screen, there can be a gap of a specified
038:         * number of pixels between the min,max values and the edges of the rectangle
039:         * on the screen.  If the gap is non-zero, then the actual range of coordinates
040:         * on the rect is larger than the range from the specifed min to max.  (This is 
041:         * done mainly so I could have axes that don't quite reach the edges of the rect.)
042:         *   <P>A CoordinateRect maintains a list of Drawable items.  When the Rect's
043:         * draw() method is called, it calls the draw() method of each of the Drawable
044:         * items it contains.  When its compute() method is called, it calls the 
045:         * compute() method of any Drawable that is a Computable.  When its checkInput()
046:         * method is called, it calls the checkInput() method of any Drawable that is
047:         * an InputObject.
048:         *   <P>A CoordinateRect represents a rectangular region in a DisplayCanvas.
049:         * It has a reference to that Canvas, which is set automatically when it is
050:         * added to the canvas.  If the size, range, or gap on the CoordinateRect
051:         * change, it will ask the Canvas to redraw the area it occupies.
052:         *
053:         * <P>The values of xmin, xmax, ymin, ymax are exported as Value objects,
054:         * which can be used elsewhere in your program.  The Value objects can
055:         * be obtained by calling getValueObject().  If you do this, you should
056:         * add the objects that depend on those values to a Controller and
057:         * register the Controller to listen for changes from this CoordinateRect
058:         * by calling the CoordinateRect.setOnChange(Controller) method.
059:         */
060:
061:        public class CoordinateRect implements  Tieable, Limits, Computable,
062:                InputObject {
063:
064:            private double xmin, xmax, ymin, ymax; // Range of x and y values on the Rect (not counting the gap).
065:
066:            private int gap = 5; //Extra pixels around the edges, outside the specifed range of x,y values.
067:            //Note: xmin,xmax,ymin,ymax are the limits on a rectangle that
068:            //is inset from the drawing rect by gap pixels on each edge.
069:
070:            /**
071:             * Drawable items contained in this CoordinateRect
072:             */
073:            protected Vector drawItems = new Vector();
074:
075:            /**
076:             * Set to true when one of the limits or the gap has changed.
077:             */
078:            protected boolean changed;
079:
080:            private long serialNumber; // This value is increased whenever xmin,xmax,ymin,ymax,gap change
081:            // or when the size of the rectangle in pixels changes.
082:
083:            /**
084:             *  This contains other Limit objects with which the CoordinateRect is
085:             *  synchronizing.  This is ordinarily managed by a LimitControlPanel,
086:             *  so you don't have to worry about it. (However, you can also sync
087:             *  several CoordinateRects even in the absense of a LimitControlPanel.
088:             *  To do so, create the Tie that ties the CoordinateRect and pass it to 
089:             *  the setSyncWith() method of each CoordinateRect.  It is NOT necessary
090:             *  to add the Tie to a Controller.  Synchronization is handled by the
091:             *  CoordinateRects themselves.   
092:             */
093:            protected Tie syncWith;
094:
095:            /**
096:             * Create a CoordinateRect with default limits: -5, 5, -5, 5.
097:             */
098:            public CoordinateRect() {
099:                this (-5, 5, -5, 5);
100:            }
101:
102:            /**
103:             * Create a CoordinateRect with specified limits.
104:             */
105:            public CoordinateRect(double xmin, double xmax, double ymin,
106:                    double ymax) {
107:                setLimits(xmin, xmax, ymin, ymax);
108:                serialNumber = 0;
109:                setRestoreBuffer(); // Restore buffer holds original limits, util it is reset
110:            }
111:
112:            //--------- Methods for getting and setting xmin, xmax, ymin, ymax, and gap.------
113:
114:            /**
115:             * Get the mimimum x-coordinate.
116:             */
117:            public double getXmin() {
118:                return xmin;
119:            }
120:
121:            /**
122:             * Get the maximum x-coordinate.
123:             */
124:            public double getXmax() {
125:                return xmax;
126:            }
127:
128:            /**
129:             * Get the mimimum y-coordinate.
130:             */
131:            public double getYmin() {
132:                return ymin;
133:            }
134:
135:            /**
136:             * Get the maximum x-coordinate.
137:             */
138:            public double getYmax() {
139:                return ymax;
140:            }
141:
142:            /**
143:             * Get the gap, in pixels, between the edges of 
144:             * the CoordinateRect and the limits specified by xmin, xmax, ymin, and ymax.
145:             */
146:            public int getGap() {
147:                return gap;
148:            }
149:
150:            /**
151:             * Set the gap. This is ignored if g is less than zero.  This gap is the number of pixels
152:             * between the edges of the CoordinateRect and the limits specified by xmin, xmax, ymin, and ymax.
153:             * The default value is 5.
154:             *
155:             */
156:            public void setGap(int g) {
157:                if (g >= 0 && gap != g) {
158:                    int oldgap = gap;
159:                    gap = g;
160:                    changed = true;
161:                    serialNumber++;
162:                    needsRedraw();
163:                }
164:            }
165:
166:            /**
167:             * Get an array containing the limits on the CoordinateRect in the order xmin, xmax, ymin, ymax.
168:             */
169:            public double[] getLimits() {
170:                return new double[] { xmin, xmax, ymin, ymax };
171:            }
172:
173:            /**
174:             * Set the limits on the CoordinteRect
175:             *
176:             * @param xmin the minimum x-coordinate on the CoordinateRect
177:             * @param xmax the maximum x-coordinate on the CoordinateRect
178:             * @param ymin the minimum y-coordinate on the CoordinateRect
179:             * @param ymax the maximum y-coordinate on the CoordinateRect
180:             */
181:            public void setLimits(double xmin, double xmax, double ymin,
182:                    double ymax) {
183:                double[] oldLimits = getLimits();
184:                this .xmin = xmin;
185:                this .xmax = xmax;
186:                this .ymin = ymin;
187:                this .ymax = ymax;
188:                checkLimits();
189:                double[] newLimits = getLimits();
190:                if (oldLimits[0] == newLimits[0]
191:                        && oldLimits[1] == newLimits[1]
192:                        && oldLimits[2] == newLimits[2]
193:                        && oldLimits[3] == newLimits[3])
194:                    return;
195:                changed = true;
196:                serialNumber++;
197:                if (syncWith != null)
198:                    syncWith.check();
199:                if (onChange != null)
200:                    onChange.compute();
201:                needsRedraw();
202:            }
203:
204:            /**
205:             * Set the coordinate limits from array; extra elements in array are ignored.
206:             * This is ignored if the array is null or has fewer than 4 members.
207:             * The order of values in the array is xmin, xmax, ymin, ymax.
208:             *
209:             */
210:            public void setLimits(double[] d) {
211:                if (d != null && d.length >= 4)
212:                    setLimits(d[0], d[1], d[2], d[3]);
213:            }
214:
215:            /**
216:             * Specify a controller to be notified when the limits on this
217:             * CoordinateRect change.
218:             */
219:            public void setOnChange(Controller c) {
220:                onChange = c;
221:            }
222:
223:            /**
224:             * Get the controller that is notified when the limits on this
225:             * CoordinateRect change.  This can be null.
226:             */
227:            public Controller getOnChange() {
228:                return onChange;
229:            }
230:
231:            /**
232:             * Get a Value object representing one of the limits on this CoordinateRect.
233:             * The parameter should be one of the constants CoordinateRect.XMIN,
234:             * CoordinateRect.XMAX, CoordinateRect.YMIN, or CoordinateRect.YMAX.
235:             * (If not, it is treated the same as YMAX).
236:             * 
237:             */
238:            public Value getValueObject(final int which) {
239:                return new Value() {
240:                    public double getVal() {
241:                        switch (which) {
242:                        case XMIN:
243:                            return getXmin();
244:                        case XMAX:
245:                            return getXmax();
246:                        case YMIN:
247:                            return getYmin();
248:                        default:
249:                            return getYmax();
250:                        }
251:                    }
252:                };
253:            }
254:
255:            /**
256:             * Return the serial number of the CoordinateRect, which is incremented each time the limits change.
257:             * Part of the Tieable interface.
258:             * Not meant to be called directly.
259:             */
260:            public long getSerialNumber() {
261:                return serialNumber;
262:            }
263:
264:            /**
265:             * Set the Tie object that is used to synchronize this CoordinareRect with other objects.
266:             * This is ordinarily called by a LimitControlPanel, so you don't have to worry about it.
267:             */
268:            public void setSyncWith(Tie tie) {
269:                syncWith = tie;
270:            }
271:
272:            /**
273:             * Part of the Tieable interface.
274:             * Not meant to be called directly.
275:             */
276:            public void sync(Tie tie, Tieable newest) {
277:                if (newest != this ) {
278:                    if (!(newest instanceof  Limits))
279:                        throw new IllegalArgumentException(
280:                                "Internal programming error:  A CoordinateRect can only be tied to a Limits object.");
281:                    double[] d = ((Limits) newest).getLimits();
282:                    if (d != null && d.length >= 4) {
283:                        double[] oldLimits = getLimits();
284:                        if (d[0] == oldLimits[0] && d[1] == oldLimits[1]
285:                                && d[2] == oldLimits[2] && d[3] == oldLimits[3])
286:                            return;
287:                        xmin = d[0];
288:                        xmax = d[1];
289:                        ymin = d[2];
290:                        ymax = d[3];
291:                        checkLimits();
292:                        serialNumber = newest.getSerialNumber();
293:                        changed = true;
294:                        if (onChange != null)
295:                            onChange.compute();
296:                        needsRedraw();
297:                    }
298:                }
299:            }
300:
301:            private void checkLimits() { //Make sure limits satisfy constraints.
302:                if (xmin == xmax) {
303:                    xmin -= 1;
304:                    xmax += 1;
305:                } else if (xmin > xmax) {
306:                    double temp = xmin;
307:                    xmin = xmax;
308:                    xmax = temp;
309:                }
310:                if (ymin == ymax) {
311:                    ymin -= 1;
312:                    ymax += 1;
313:                }
314:                if (ymin > ymax) {
315:                    double temp = ymin;
316:                    ymin = ymax;
317:                    ymax = temp;
318:                }
319:            }
320:
321:            // -------------- Value objects corresponding to xmin, xmax, ymin, ymax -------------
322:
323:            /**
324:             * A constant for use with the getValueObject() method to specify which Value is to be returned.
325:             * XMIN specifies that the Value is the minimum x-coordinate on the CoordinateRect.
326:             */
327:            public final static int XMIN = 0;
328:
329:            /**
330:             * A constant for use with the getValueObject() method to specify which Value is to be returned.
331:             * XMAX specifies that the Value is the maximum x-coordinate on the CoordinateRect.
332:             */
333:            public final static int XMAX = 1;
334:
335:            /**
336:             * A constant for use with the getValueObject() method to specify which Value is to be returned.
337:             * YMIN specifies that the Value is the minimum y-coordinate on the CoordinateRect.
338:             */
339:            public final static int YMIN = 2;
340:
341:            /**
342:             * A constant for use with the getValueObject() method to specify which Value is to be returned.
343:             * YMAX specifies that the Value is the maximum y-coordinate on the CoordinateRect.
344:             */
345:            public final static int YMAX = 3;
346:
347:            /**
348:             * If non-null, this is the Controller that is notified when the limits change. 
349:             */
350:            protected Controller onChange;
351:
352:            // ---------------------- Methods for working with Pixels ----------------------
353:            // Note: This stuff is only valid if the CoordinateRect is
354:            // displayed in a Graphics context.  I.E., after a call to draw();
355:            // It is meant to be used by Drawables when their draw() methods are called.
356:
357:            private int left, top, width = -1, height = -1; // Not setable; these are valid only during drawing and are meant to be used
358:
359:            // by the Drawables in this Coorfdinate Rect.
360:
361:            /**
362:             * Get the left edge of this CoordinateRect in the DisplayCanvas that contains it.
363:             * (This is only valid when the CoordinateRect has actually been displayed.  It is meant
364:             * mainly to be used by Drawables in this CoordinateRect.)
365:             */
366:            public int getLeft() {
367:                return left;
368:            }
369:
370:            /**
371:             * Get the width in pixels of this CoordinateRect in the DisplayCanvas that contains it.
372:             * (This is only valid when the CoordinateRect has actually been displayed.  It is meant
373:             * mainly to be used by Drawables in this CoordinateRect.)
374:             */
375:            public int getWidth() {
376:                return width;
377:            }
378:
379:            /**
380:             * Get the top edge of this CoordinateRect in the DisplayCanvas that contains it.
381:             * (This is only valid when the CoordinateRect has actually been displayed.  It is meant
382:             * mainly to be used by Drawables in this CoordinateRect.)
383:             */
384:            public int getTop() {
385:                return top;
386:            }
387:
388:            /**
389:             * Get the height in pixels of this CoordinateRect in the DisplayCanvas that contains it.
390:             * (This is only valid when the CoordinateRect has actually been displayed.  It is meant
391:             * mainly to be used by Drawables in this CoordinateRect.)
392:             */
393:            public int getHeight() {
394:                return height;
395:            }
396:
397:            /**
398:             * Return the width of one pixel in this coordinate system.
399:             * (This is only valid when the CoordinateRect has actually been displayed.  It is meant
400:             * mainly to be used by Drawables in this CoordinateRect.)
401:             *
402:             */
403:            public double getPixelWidth() {
404:                return (xmax - xmin) / (width - 2 * gap - 1);
405:            }
406:
407:            /**
408:             * Return the height of one pixel in this coordinate system.
409:             * (This is only valid when the CoordinateRect has actually been displayed.  It is meant
410:             * mainly to be used by Drawables in this CoordinateRect.)
411:             * 
412:             */
413:            public double getPixelHeight() {
414:                return (ymax - ymin) / (height - 2 * gap - 1);
415:            }
416:
417:            /**
418:             * Convert an x-coodinate into a horizontal pixel coordinate.
419:             * (This is only valid when the CoordinateRect has actually been displayed.  It is meant
420:             * mainly to be used by Drawables in this CoordinateRect.)
421:             * 
422:             */
423:            public int xToPixel(double x) {
424:                int xInt = left
425:                        + gap
426:                        + (int) ((x - xmin) / (xmax - xmin) * (width - 2 * gap - 1));
427:                if (xInt < -32000)
428:                    return -32000;
429:                else if (xInt > 32000)
430:                    return 32000;
431:                else
432:                    return xInt;
433:            }
434:
435:            /**
436:             * Convert a y-coodinate into a vertical pixel coordinate.
437:             * (This is only valid when the CoordinateRect has actually been displayed.  It is meant
438:             * mainly to be used by Drawables in this CoordinateRect.)
439:             * 
440:             */
441:            public int yToPixel(double y) {
442:                int yInt = top
443:                        + gap
444:                        + (int) ((ymax - y) / (ymax - ymin) * (height - 2 * gap - 1));
445:                if (yInt < -32000)
446:                    return -32000;
447:                else if (yInt > 32000)
448:                    return 32000;
449:                else
450:                    return yInt;
451:            }
452:
453:            /**
454:             * Convert a horizontal pixel coordinate into an x-coordinate.
455:             * (This is only valid when the CoordinateRect has actually been displayed.  It is meant
456:             * mainly to be used by Drawables in this CoordinateRect.)
457:             * 
458:             */
459:            public double pixelToX(int h) {
460:                return xmin + ((h - left - gap) * (xmax - xmin))
461:                        / (width - 2 * gap - 1);
462:            }
463:
464:            /**
465:             * Convert a vertical pixel coordinate into a y-coordinate.
466:             * (This is only valid when the CoordinateRect has actually been displayed.  It is meant
467:             * mainly to be used by Drawables in this CoordinateRect.)
468:             * 
469:             */
470:            public double pixelToY(int y) {
471:                return ymax - ((y - top - gap) * (ymax - ymin))
472:                        / (height - 2 * gap - 1);
473:            }
474:
475:            // ---------------------- Save/Restore limits -------------------------
476:
477:            private double restore_xmin = Double.NaN, restore_xmax,
478:                    restore_ymin, restore_ymax;
479:
480:            /**
481:             * A CoordinateRect can store its current limits in a buffer.  These limits
482:             * can be restored by a call to this method.  Only one level of 
483:             * save/restore is provided. If limits have not been saved, then nothing happens.
484:             * The original limits on the CoordinateRect are saves automatically when
485:             * the CoordinateRect is first created.
486:             *
487:             * @return an array containing new limits.
488:             */
489:            public double[] restore() {
490:                if (Double.isNaN(restore_xmin))
491:                    return null;
492:                setLimits(restore_xmin, restore_xmax, restore_ymin,
493:                        restore_ymax);
494:                return getLimits();
495:            }
496:
497:            /**
498:             * A CoordinateRect can store its current limits in a buffer.  This method
499:             * clears that buffer.
500:             */
501:            public void clearRestoreBuffer() {
502:                restore_xmin = Double.NaN;
503:            }
504:
505:            /**
506:             * Save current limits in buffer.  They can be restored later by a call
507:             * to the restore() method. Only one level of 
508:             * save/restore is provided.
509:             */
510:            public void setRestoreBuffer() {
511:                if (badData())
512:                    return;
513:                checkLimits();
514:                restore_xmin = xmin;
515:                restore_xmax = xmax;
516:                restore_ymin = ymin;
517:                restore_ymax = ymax;
518:            }
519:
520:            /**
521:             * Used to test if any of the limit data are infinite or NaN.
522:             */
523:            private boolean badData() {
524:                return Double.isNaN(xmin) || Double.isInfinite(xmin)
525:                        || Double.isNaN(ymin) || Double.isInfinite(ymin)
526:                        || Double.isNaN(xmax) || Double.isInfinite(xmax)
527:                        || Double.isNaN(ymax) || Double.isInfinite(ymax);
528:            }
529:
530:            // ----------- Zoom in and out ---------------
531:
532:            /**
533:             * Change limits to zoom in by a factor of 2.  A maximal zoom is enforced.
534:             * The center of the rectangle does not move.
535:             *
536:             * @return an array of the new limits, or null if limits don't change.
537:             */
538:            public double[] zoomIn() {
539:                if (badData())
540:                    return getLimits();
541:                double halfwidth = (xmax - xmin) / 4.0;
542:                double halfheight = (ymax - ymin) / 4.0;
543:                double centerx = (xmin + xmax) / 2.0;
544:                double centery = (ymin + ymax) / 2.0;
545:                if (Math.abs(halfheight) < 1e-100
546:                        || Math.abs(halfwidth) < 1e-100)
547:                    return null;
548:                setLimits(centerx - halfwidth, centerx + halfwidth, centery
549:                        - halfheight, centery + halfheight);
550:                return getLimits();
551:            }
552:
553:            /**
554:             * Change limits to zoom out by a factor of 2.  A maximal zoom is enforced.
555:             * The center of the rectangle does not move.
556:             * 
557:             * @return an array of the new limits, or null if limits don't change.
558:             */
559:            public double[] zoomOut() {
560:                if (badData())
561:                    return getLimits();
562:                double halfwidth = (xmax - xmin);
563:                double halfheight = (ymax - ymin);
564:                double centerx = (xmin + xmax) / 2.0;
565:                double centery = (ymin + ymax) / 2.0;
566:                if (Math.abs(halfwidth) > 1e100 || Math.abs(halfheight) > 1e100)
567:                    return null;
568:                setLimits(centerx - halfwidth, centerx + halfwidth, centery
569:                        - halfheight, centery + halfheight);
570:                return getLimits();
571:            }
572:
573:            /**
574:             * Change limits to zoom in by a factor of 2, centered on a specified point.  A maximal zoom is enforced.
575:             * The point does not move.  Only valid when CoordinateRect is
576:             * displayed in a rectangle on the screen.
577:             *
578:             * @param x the horizontal pixel coordinate of the center point of the zoom
579:             * @param y the vertical pixel coordinate of the center point of the zoom
580:             *
581:             * @return an array of the new limits, or null if limits don't change.
582:             */
583:            public double[] zoomInOnPixel(int x, int y) {
584:                if (badData())
585:                    return getLimits();
586:                double halfwidth = (xmax - xmin) / 4.0;
587:                double halfheight = (ymax - ymin) / 4.0;
588:                if (Math.abs(halfheight) < 1e-100
589:                        || Math.abs(halfwidth) < 1e-100)
590:                    return null;
591:                double xclick = pixelToX(x);
592:                double yclick = pixelToY(y);
593:                double centerx = (xmin + xmax) / 2;
594:                double centery = (ymin + ymax) / 2;
595:                double newCenterx = (centerx + xclick) / 2;
596:                double newCentery = (centery + yclick) / 2;
597:                setLimits(newCenterx - halfwidth, newCenterx + halfwidth,
598:                        newCentery - halfheight, newCentery + halfheight);
599:                return getLimits();
600:            }
601:
602:            /**
603:             * Change limits to zoom out by a factor of 2, centered on a specified point.  A maximal zoom is enforced.
604:             * The point (x,y) does not move.  Valid only if CoordinateRect has been drawn.
605:             *
606:             * @param x the horizontal pixel coordinate of the center point of the zoom
607:             * @param y the vertical pixel coordinate of the center point of the zoom
608:             *
609:             * @return an array of the new limits, or null if limits don't change.
610:             */
611:            public double[] zoomOutFromPixel(int x, int y) {
612:                if (badData())
613:                    return getLimits();
614:                double halfwidth = (xmax - xmin);
615:                double halfheight = (ymax - ymin);
616:                if (Math.abs(halfwidth) > 1e100 || Math.abs(halfheight) > 1e100)
617:                    return null;
618:                double xclick = pixelToX(x);
619:                double yclick = pixelToY(y);
620:                double centerx = (xmin + xmax) / 2;
621:                double centery = (ymin + ymax) / 2;
622:                double newCenterx = 2 * centerx - xclick;
623:                double newCentery = 2 * centery - yclick;
624:                setLimits(newCenterx - halfwidth, newCenterx + halfwidth,
625:                        newCentery - halfheight, newCentery + halfheight);
626:                return getLimits();
627:            }
628:
629:            /**
630:             * Reset limits, if necessary, so scales on the axes are the same.
631:             * Only valid of the CoordinateRect has been drawn.  
632:             *
633:             * @return an array with the new limits, or null if limits don't change.
634:             */
635:            public double[] equalizeAxes() {
636:                if (badData())
637:                    return getLimits();
638:                double w = xmax - xmin;
639:                double h = ymax - ymin;
640:                double pixelWidth = w / (width - 2 * gap - 1);
641:                double pixelHeight = h / (height - 2 * gap - 1);
642:                double newXmin, newXmax, newYmin, newYmax;
643:                if (pixelWidth < pixelHeight) {
644:                    double centerx = (xmax + xmin) / 2;
645:                    double halfwidth = w / 2 * pixelHeight / pixelWidth;
646:                    newXmax = centerx + halfwidth;
647:                    newXmin = centerx - halfwidth;
648:                    newYmin = ymin;
649:                    newYmax = ymax;
650:                } else if (pixelWidth > pixelHeight) {
651:                    double centery = (ymax + ymin) / 2;
652:                    double halfheight = h / 2 * pixelWidth / pixelHeight;
653:                    newYmax = centery + halfheight;
654:                    newYmin = centery - halfheight;
655:                    newXmin = xmin;
656:                    newXmax = xmax;
657:                } else
658:                    return null;
659:                setLimits(newXmin, newXmax, newYmin, newYmax);
660:                return getLimits();
661:            }
662:
663:            // ------------------------------ Drawing ----------------------------
664:
665:            private DisplayCanvas canvas; // The canvas in which this CoordinateRect is displayed.  This is set
666:
667:            // automatically when the CoordinateRect is added to or removed from
668:            // a DisplayCanvas, and it should not be changed.
669:
670:            /**
671:             * This is meant to be called only by the DisplayCanvas class,
672:             * when this CoordinateRect is added to ta DisplayCanvas.
673:             * 
674:             */
675:            void setOwner(DisplayCanvas canvas) {
676:                this .canvas = canvas;
677:            }
678:
679:            private void needsRedraw() { //Notifies the canvas that the area occupied by this CoodinateRect
680:                if (canvas != null) //needs to be redrawn.
681:                    canvas.doRedraw(this );
682:            }
683:
684:            /**
685:             * When this is called, the CoordinateRect will call the
686:             * checkInput method of any Drawable it contains that is
687:             * also an InputObject.  This is ordinarly only called by a DisplayCanvas.
688:             */
689:            public void checkInput() {
690:                int ct = drawItems.size();
691:                for (int i = 0; i < ct; i++)
692:                    if (drawItems.elementAt(i) instanceof  InputObject)
693:                        ((InputObject) drawItems.elementAt(i)).checkInput();
694:            }
695:
696:            /**
697:             * When this is called, the CoordinateRect will call the compute method
698:             * of any Drawable it contains that is also a Computable.
699:             *  This is ordinarly only called by a DisplayCanvas.
700:             */
701:            public void compute() {
702:                int ct = drawItems.size();
703:                for (int i = 0; i < ct; i++)
704:                    if (drawItems.elementAt(i) instanceof  Computable)
705:                        ((Computable) drawItems.elementAt(i)).compute();
706:            }
707:
708:            /**
709:             * Method required by InputObject interface; in this class, it calls the same method
710:             * recursively on any input objects containted in this CoordinateRect.  This is meant to 
711:             * be called by JCMPanel.gatherInputs().
712:             */
713:            public void notifyControllerOnChange(Controller c) {
714:                int ct = drawItems.size();
715:                for (int i = 0; i < ct; i++)
716:                    if (drawItems.elementAt(i) instanceof  InputObject)
717:                        ((InputObject) drawItems.elementAt(i))
718:                                .notifyControllerOnChange(c);
719:            }
720:
721:            /**
722:             * Add a drawable item to the CoordinateRect.
723:             *
724:             */
725:            synchronized public void add(Drawable d) {
726:                if (d != null && !drawItems.contains(d)) {
727:                    d.setOwnerData(canvas, this );
728:                    drawItems.addElement(d);
729:                }
730:            }
731:
732:            /** 
733:             * Remove the given Drawable item, if present in this CoordinateRect.
734:             * 
735:             */
736:            synchronized public void remove(Drawable d) {
737:                if (d != null && drawItems.removeElement(d))
738:                    d.setOwnerData(null, null);
739:            }
740:
741:            /**
742:             * Returns the number of Drawable items that are in this CoordinateRect.
743:             */
744:            public int getDrawableCount() {
745:                return (drawItems == null) ? 0 : drawItems.size();
746:            }
747:
748:            /**
749:             * Get the i-th Drawable in this Rect, or null if i is less than zero
750:             * or greater than or equal to the number of items.
751:             *
752:             * @param i The number of the item to be returned, where the first item is number zero.
753:             */
754:            public Drawable getDrawable(int i) {
755:                if (drawItems != null && i >= 0 && i < drawItems.size())
756:                    return (Drawable) drawItems.elementAt(i);
757:                else
758:                    return null;
759:            }
760:
761:            /**
762:             * Check whether a mouse click (as specified in the MouseEvent parameter) is
763:             * a click on a Draggable item that wants to be dragged.  If so, return that item.  If not, return null.
764:             * This is meant to be called only by DisplayCanvas.
765:             */
766:            Draggable checkDraggables(java.awt.event.MouseEvent evt) {
767:                int top = drawItems.size();
768:                for (int i = top - 1; i >= 0; i--)
769:                    if (drawItems.elementAt(i) instanceof  Draggable) {
770:                        if (((Draggable) drawItems.elementAt(i)).startDrag(evt))
771:                            return (Draggable) drawItems.elementAt(i);
772:                    }
773:                return null;
774:            }
775:
776:            /**
777:             * Draw in rect with upperleft corner (0,0) and specified width,height.
778:             * This is not ordinarily called directly.
779:             *
780:             */
781:            public void draw(Graphics g, int width, int height) {
782:                draw(g, 0, 0, width, height);
783:            }
784:
785:            /**
786:             * Draw in specified rect.  This is not ordinarily called directly.
787:             */
788:            synchronized public void draw(Graphics g, int left, int top,
789:                    int width, int height) {
790:                if (badData()) {
791:                    g.setColor(Color.red);
792:                    g.drawRect(left, top, width - 1, height - 1);
793:                    g.drawString("(undefined limits)", left + 6, top + 15);
794:                }
795:                if (changed || this .left != left || this .top != top
796:                        || this .width != width || this .height != height) {
797:                    this .width = width;
798:                    this .height = height;
799:                    this .left = left;
800:                    this .top = top;
801:                    checkLimits();
802:                    changed = true;
803:                }
804:                doDraw(g);
805:                changed = false;
806:            }
807:
808:            /**
809:             * Draw all the Drawable items.  This is called by the draw() method and is not 
810:             * meant to be called directly.  However, it might be overridden in a subclass.
811:             *
812:             */
813:            protected void doDraw(Graphics g) {
814:                int ct = drawItems.size();
815:                for (int i = 0; i < ct; i++) {
816:                    Drawable d = (Drawable) drawItems.elementAt(i);
817:                    if (d.getVisible())
818:                        d.draw(g, changed);
819:                }
820:            }
821:
822:        } // end class CoordinateRect
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.