root/trunk/ObjectPainter.java
| Revision 136, 5.3 kB (checked in by tfelker2, 3 years ago) | |
|---|---|
| |
| Line | |
|---|---|
| 1 | /** |
| 2 | * ObjectPainter.java |
| 3 | * |
| 4 | * This class represents ways in which objects, such as PhysicalNodes and |
| 5 | * PhysicalEdges, can be drawn on the screen. Instances of it will actually |
| 6 | * perform this drawing, as well as participate in the mouseclick resolution |
| 7 | * process. Subclasses will specialize in painting objects of certain types, |
| 8 | * and may throw exceptions when asked to paint other types of objects. This |
| 9 | * class is not abstract, but it performs no specific action, thus, objects |
| 10 | * can be made invisible by causing them to be painted by instances of this |
| 11 | * class. |
| 12 | * |
| 13 | * This is somewhat inefficient because each object drawn requires three virtual |
| 14 | * method calls and several casts, but as a result, there is no need for code |
| 15 | * duplication in any of the subclasses. |
| 16 | * |
| 17 | * Also, it's possible to set the AffineTransform in a Graphics2D object before |
| 18 | * using the ObjectPainter, in which case ObjectPainter would no longer need to |
| 19 | * use AffineTransforms. However, this scales everything, including line |
| 20 | * thickness and circle radius, so the implementation would actually be a |
| 21 | * little more complex to compensate for that. I don't think that affects |
| 22 | * efficiency much, but more research is needed. |
| 23 | * |
| 24 | * Other possible optimizations, all of which are somewhat dirty, include: using |
| 25 | * protected members instead of passing things on the stack, removing |
| 26 | * needToPaint(), and instead giving computeLocation a Graphics2D (precluding |
| 27 | * its use in visualDistanceTo()) and letting it return null if !needToPaint(). |
| 28 | * Performance benchmarks are needed - though most of the problems come from |
| 29 | * antialiasing, I think. |
| 30 | */ |
| 31 | |
| 32 | import java.awt.*; |
| 33 | import java.awt.geom.*; |
| 34 | import java.util.*; |
| 35 | |
| 36 | public class ObjectPainter { |
| 37 | |
| 38 | /// An instance can paint every type, but won't actually do anything. |
| 39 | public ObjectPainter() {} |
| 40 | |
| 41 | /** |
| 42 | * Draws object, translated according to realToScreen, on g. |
| 43 | */ |
| 44 | public final void paintObject(Object object, AffineTransform realToScreen, BackgroundMap map, Graphics2D g) { |
| 45 | if(!visible) return; |
| 46 | // compute, using the transform, the location of the object onscreen |
| 47 | // in our subclasses, the location will probably be a point or line |
| 48 | Object location = computeLocation(object, realToScreen); |
| 49 | // quit if we don't need to paint the object |
| 50 | if(!needToPaint(object, location, map, g)) return; |
| 51 | // set the color, etc... |
| 52 | setupPainting(g); |
| 53 | // paint the object... |
| 54 | paintSingleObject(object, location, g); |
| 55 | } |
| 56 | |
| 57 | /** |
| 58 | * Draws all given objects, translated according to realToScreen, on g |
| 59 | */ |
| 60 | public final void paintObjects(Collection objects, AffineTransform realToScreen, BackgroundMap map, |
| 61 | Graphics2D g) { |
| 62 | if(!visible) return; |
| 63 | |
| 64 | // set the color, etc... |
| 65 | setupPainting(g); |
| 66 | |
| 67 | // for all the objects we're given... |
| 68 | Iterator iterator = objects.iterator(); |
| 69 | while(iterator.hasNext()) { |
| 70 | Object object = iterator.next(); |
| 71 | // figure out where on the screen it should be painted |
| 72 | Object location = computeLocation(object, realToScreen); |
| 73 | // if we don't need to draw this node, go on to the next |
| 74 | if(!needToPaint(object, location, map, g)) continue; |
| 75 | // paint it |
| 76 | paintSingleObject(object, location, g); |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | /* |
| 81 | * The following private methods should be overridden in subclasses |
| 82 | * to implement the drawing of their specific types of objects. They |
| 83 | * can throw ClassCastExceptions if they are asked to act upon objects |
| 84 | * they don't know how to paint. |
| 85 | */ |
| 86 | |
| 87 | /** |
| 88 | * Returns how far (in pixels) from the onscreen visual representation |
| 89 | * of the object the given point is. If the point is on the object, the |
| 90 | * distance should be less than or equal to zero. This is used to allow |
| 91 | * smart detection of mouseclicks on or near an object. |
| 92 | */ |
| 93 | |
| 94 | public double visualDistanceTo(Object object, Point2D.Double real, BackgroundMap map, AffineTransform realToScreen) { |
| 95 | return Double.POSITIVE_INFINITY; |
| 96 | } |
| 97 | |
| 98 | /** |
| 99 | * Whether the object should actually be drawn. |
| 100 | */ |
| 101 | public void setVisible(boolean v) { visible = v; } |
| 102 | public boolean getVisible() { return visible; } |
| 103 | |
| 104 | private boolean visible = true; |
| 105 | |
| 106 | /** |
| 107 | * This sets up the Graphics2D context to draw any number of points in |
| 108 | * the style this ObjectPainter represents. In the future, this could |
| 109 | * become non-trivial, so we allow for multiple objects to be painted |
| 110 | * in the same style while only doing this once. This is where you set |
| 111 | * the color, for example. |
| 112 | */ |
| 113 | protected void setupPainting(Graphics2D g) {} |
| 114 | |
| 115 | /** |
| 116 | * This computes the location the object will be drawn on screen, which |
| 117 | * should be the object's location transformed by realToScreen. The |
| 118 | * location will usually be a Point or Line in subclasses, it is Object |
| 119 | * here because that is their common ancestor. The returned location |
| 120 | * will be passed to needToPaint() and paintSingleObject(). |
| 121 | */ |
| 122 | protected Object computeLocation(Object object, AffineTransform realToScreen) { return null; } |
| 123 | |
| 124 | /** |
| 125 | * This must return true if the object, when painted, would be visible |
| 126 | * (i.e. would be inside g's clipping region). It can return true |
| 127 | * otherwise also, which will cause unnecessary but harmless painting. |
| 128 | */ |
| 129 | protected boolean needToPaint(Object object, Object location, BackgroundMap map, Graphics2D g) { |
| 130 | return false; |
| 131 | } |
| 132 | |
| 133 | /** |
| 134 | * This paints object on g at the given location. |
| 135 | */ |
| 136 | protected void paintSingleObject(Object object, Object location, Graphics2D g) {} |
| 137 | |
| 138 | } |
Note: See TracBrowser for help on using the browser.
