root/trunk/ObjectPainter.java

Revision 136, 5.3 kB (checked in by tfelker2, 3 years ago)

The mapeditor is now fully working with both types of maps. Next, i'll add a way to change node's names, then come elevators and stairways.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
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.