Coverage details for edu.uci.ics.jung.visualization.PluggableRenderer

LineHitsSource
1 /*
2  * Copyright (c) 2003, the JUNG Project and the Regents of the University of
3  * California All rights reserved.
4  *
5  * This software is open-source under the BSD license; see either "license.txt"
6  * or http://jung.sourceforge.net/license.txt for a description.
7  */
8 package edu.uci.ics.jung.visualization;
9  
10 import java.awt.BasicStroke;
11 import java.awt.Color;
12 import java.awt.Component;
13 import java.awt.Dimension;
14 import java.awt.Font;
15 import java.awt.Graphics;
16 import java.awt.Graphics2D;
17 import java.awt.Paint;
18 import java.awt.Rectangle;
19 import java.awt.Shape;
20 import java.awt.Stroke;
21 import java.awt.geom.AffineTransform;
22 import java.awt.geom.Ellipse2D;
23 import java.awt.geom.GeneralPath;
24 import java.awt.geom.Line2D;
25 import java.awt.geom.PathIterator;
26 import java.awt.geom.Point2D;
27 import java.awt.geom.Rectangle2D;
28  
29 import javax.swing.CellRendererPane;
30 import javax.swing.Icon;
31 import javax.swing.JComponent;
32  
33 import org.apache.commons.collections.Predicate;
34 import org.apache.commons.collections.functors.TruePredicate;
35  
36 import edu.uci.ics.jung.graph.ArchetypeEdge;
37 import edu.uci.ics.jung.graph.ArchetypeVertex;
38 import edu.uci.ics.jung.graph.Edge;
39 import edu.uci.ics.jung.graph.Graph;
40 import edu.uci.ics.jung.graph.UndirectedEdge;
41 import edu.uci.ics.jung.graph.Vertex;
42 import edu.uci.ics.jung.graph.decorators.ConstantDirectionalEdgeValue;
43 import edu.uci.ics.jung.graph.decorators.ConstantEdgeFontFunction;
44 import edu.uci.ics.jung.graph.decorators.ConstantEdgePaintFunction;
45 import edu.uci.ics.jung.graph.decorators.ConstantEdgeStringer;
46 import edu.uci.ics.jung.graph.decorators.ConstantEdgeStrokeFunction;
47 import edu.uci.ics.jung.graph.decorators.ConstantVertexAspectRatioFunction;
48 import edu.uci.ics.jung.graph.decorators.ConstantVertexFontFunction;
49 import edu.uci.ics.jung.graph.decorators.ConstantVertexSizeFunction;
50 import edu.uci.ics.jung.graph.decorators.ConstantVertexStringer;
51 import edu.uci.ics.jung.graph.decorators.ConstantVertexStrokeFunction;
52 import edu.uci.ics.jung.graph.decorators.DirectionalEdgeArrowFunction;
53 import edu.uci.ics.jung.graph.decorators.EdgeArrowFunction;
54 import edu.uci.ics.jung.graph.decorators.EdgeColorFunction;
55 import edu.uci.ics.jung.graph.decorators.EdgeFontFunction;
56 import edu.uci.ics.jung.graph.decorators.EdgePaintFunction;
57 import edu.uci.ics.jung.graph.decorators.EdgeShape;
58 import edu.uci.ics.jung.graph.decorators.EdgeShapeFunction;
59 import edu.uci.ics.jung.graph.decorators.EdgeStringer;
60 import edu.uci.ics.jung.graph.decorators.EdgeStrokeFunction;
61 import edu.uci.ics.jung.graph.decorators.EllipseVertexShapeFunction;
62 import edu.uci.ics.jung.graph.decorators.NumberEdgeValue;
63 import edu.uci.ics.jung.graph.decorators.PickableVertexPaintFunction;
64 import edu.uci.ics.jung.graph.decorators.VertexColorFunction;
65 import edu.uci.ics.jung.graph.decorators.VertexFontFunction;
66 import edu.uci.ics.jung.graph.decorators.VertexIconFunction;
67 import edu.uci.ics.jung.graph.decorators.VertexPaintFunction;
68 import edu.uci.ics.jung.graph.decorators.VertexShapeFunction;
69 import edu.uci.ics.jung.graph.decorators.VertexStringer;
70 import edu.uci.ics.jung.graph.decorators.VertexStrokeFunction;
71 import edu.uci.ics.jung.graph.predicates.EdgePredicate;
72 import edu.uci.ics.jung.graph.predicates.SelfLoopEdgePredicate;
73 import edu.uci.ics.jung.utils.Pair;
74 import edu.uci.ics.jung.utils.ParallelEdgeIndexFunction;
75 import edu.uci.ics.jung.utils.ParallelEdgeIndexSingleton;
76 import edu.uci.ics.jung.visualization.transform.MutableAffineTransformer;
77 import edu.uci.ics.jung.visualization.transform.MutableTransformer;
78  
79 /**
80  * <p>A renderer with all sorts of buttons to press and dials to turn.
81  * Using the appropriate methods, the user can override the default
82  * properties/behaviors for vertex paint, stroke, shape, label, label font,
83  * and label centering; and for edge paint, stroke, label, arrows, label font,
84  * label positioning, and drawing.
85  * </p>
86  * <p>Notes on these decorators:
87  * <ul>
88  * <li/>The decorators are all orthogonal; changing one does not change the behavior of any
89  * other (unless your decorator implementations depend on one another).
90  * <li/>The default properties apply to each vertices/edges, but the decorators allow these
91  * properties to be specified individually for each vertex/edge. See the documentation for
92  * each of these decorators for specific instructions on their use.
93  * <li/>Implementations of these decorator interfaces are provided that allow the user
94  * to specify a single (constant) property to apply to all vertices/edges.
95  * <li/>There are additional interfaces and classes that allow the size and aspect ratio
96  * of the vertex shape to be independently manipulated, and that provide factory methods
97  * for generating various standard shapes; see <code>SettableVertexShapeFunction</code>,
98  * <code>AbstractVertexShapeFunction</code>, <code>VertexShapeFactory</code>, and the
99  * sample <code>samples.graph.PluggableRendererDemo</code>.
100  * <li/>This class provides default <code>Stroke</code> implementations for dotted and
101  * dashed lines: the <code>DOTTED</code> and <code>DASHED</code> static constants,
102  * respectively.
103  * <li/>The <code>EdgeArrowPredicate</code> specifies the edges for which arrows
104  * should be drawn; the <code>EdgeArrowFunction</code> specifies the shapes of
105  * the arrowheads for those edges that pass the <code>EdgeArrowPredicate</code>.
106  * <li/>If the specified vertex inclusion <code>Predicate</code> indicates that
107  * vertex <code>v</code> is not to be drawn, none of its incident edges will be drawn either.
108  * </ul>
109  *
110  * <p>By default, self-loops are drawn as circles.</p>
111  *
112  * <p>By default, undirected edges are drawn as straight lines, directed edges are
113  * drawn as bent lines, and parallel edges are drawn on top
114  * of one another.</p>
115  
116  * <p>Arrowheads are drawn so that the point of the arrow is at the boundary of the
117  * vertex shapes. In the current implementation, finding the place
118  * where arrows are drawn is fairly slow; for large graphs, this should
119  * be turned off.</p>
120  *
121  * <p>Setting a stroke width other than 1, or using transparency,
122  * may slow down rendering of the visualization.
123  * </p>
124  *
125  * @author Danyel Fisher
126  * @author Joshua O'Madadhain
127  * @author Tom Nelson
128  */
129 public class PluggableRenderer extends AbstractRenderer implements PickedInfo, HasShapeFunctions
130 {
131     
1320    protected float arrow_placement_tolerance = 1;
1330    protected final static float[] dotting = {1.0f, 3.0f};
134     /**
135      * A stroke for a dotted line: 1 pixel width, round caps, round joins, and an
136      * array of {1.0f, 3.0f}.
137      */
1380    public final static Stroke DOTTED = new BasicStroke(1.0f, BasicStroke.CAP_ROUND,
139             BasicStroke.JOIN_ROUND, 1.0f, dotting, 0f);
140  
1410    protected final static float[] dashing = {5.0f};
142     /**
143      * A stroke for a dashed line: 1 pixel width, square caps, beveled joins, and an
144      * array of {5.0f}.
145      */
1460    public final static Stroke DASHED = new BasicStroke(1.0f, BasicStroke.CAP_SQUARE,
147             BasicStroke.JOIN_BEVEL, 1.0f, dashing, 0f);
148     
149     /**
150      * Specifies the offset for the edge labels.
151      */
152     public static final int LABEL_OFFSET = 10;
153  
154     /**
155      * Specifies the maximum number of iterations to run the edge subdivision loop
156      * in <code>getLastOutsideSegment</code>; this is done to fix the arrow
157      * orientation problem noted in bug report #1450529.
158      */
159     protected static final int MAX_ITERATIONS = 10;
160     
1610    protected Predicate vertexIncludePredicate = TruePredicate.getInstance();
1620    protected VertexStrokeFunction vertexStrokeFunction =
163         new ConstantVertexStrokeFunction(1.0f);
1640    protected VertexShapeFunction vertexShapeFunction =
165         new EllipseVertexShapeFunction(
166                 new ConstantVertexSizeFunction(20),
167                 new ConstantVertexAspectRatioFunction(1.0f));
1680    protected VertexStringer vertexStringer =
169         new ConstantVertexStringer(null);
170     protected VertexIconFunction vertexIconFunction;
1710    protected VertexFontFunction vertexFontFunction =
172         new ConstantVertexFontFunction(new Font("Helvetica", Font.PLAIN, 12));
1730    protected boolean centerVertexLabel = false;
174     
1750    protected VertexPaintFunction vertexPaintFunction =
176         new PickableVertexPaintFunction(this, Color.BLACK, Color.RED, Color.ORANGE);
177     
1780    protected EdgeStringer edgeStringer =
179         new ConstantEdgeStringer(null);
1800    protected EdgeStrokeFunction edgeStrokeFunction =
181         new ConstantEdgeStrokeFunction(1.0f);
1820    protected EdgeArrowFunction edgeArrowFunction =
183         new DirectionalEdgeArrowFunction(10, 8, 4);
1840    protected Predicate edgeArrowPredicate = Graph.DIRECTED_EDGE;
1850    protected Predicate edgeIncludePredicate = TruePredicate.getInstance();
1860    protected EdgeFontFunction edgeFontFunction =
187         new ConstantEdgeFontFunction(new Font("Helvetica", Font.PLAIN, 12));
1880    protected NumberEdgeValue edgeLabelClosenessFunction =
189         new ConstantDirectionalEdgeValue(0.5, 0.65);
1900    protected EdgeShapeFunction edgeShapeFunction =
191         new EdgeShape.QuadCurve();
1920    protected EdgePaintFunction edgePaintFunction =
193         new ConstantEdgePaintFunction(Color.black, null);
1940    protected ParallelEdgeIndexFunction parallelEdgeIndexFunction =
195         ParallelEdgeIndexSingleton.getInstance();
1960    protected MutableTransformer viewTransformer = new MutableAffineTransformer();
197     
198     /**
199      * the JComponent that this Renderer will display the graph on
200      */
201     protected JComponent screenDevice;
202     
203     /**
204      * The CellRendererPane is used here just as it is in JTree
205      * and JTable, to allow a pluggable JLabel-based renderer for
206      * Vertex and Edge label strings and icons.
207      */
2080    protected CellRendererPane rendererPane = new CellRendererPane();
209     
210     /**
211      * A default GraphLabelRenderer - picked Vertex labels are
212      * blue, picked edge labels are cyan
213      */
2140    protected GraphLabelRenderer graphLabelRenderer =
215         new DefaultGraphLabelRenderer(Color.blue, Color.cyan);
216     
2170    protected final static EdgePredicate self_loop = SelfLoopEdgePredicate.getInstance();
218     
219     public PluggableRenderer()
2200    {
2210        this.setEdgeShapeFunction(new EdgeShape.QuadCurve());
2220    }
223     
224     /**
225      * @return Returns the edgeArrowFunction.
226      */
227     public EdgeArrowFunction getEdgeArrowFunction() {
2280        return edgeArrowFunction;
229     }
230  
231     /**
232      * @return Returns the edgeArrowPredicate.
233      */
234     public Predicate getEdgeArrowPredicate() {
2350        return edgeArrowPredicate;
236     }
237  
238     /**
239      * @return Returns the edgeFontFunction.
240      */
241     public EdgeFontFunction getEdgeFontFunction() {
2420        return edgeFontFunction;
243     }
244  
245     /**
246      * @return Returns the edgeIncludePredicate.
247      */
248     public Predicate getEdgeIncludePredicate() {
2490        return edgeIncludePredicate;
250     }
251  
252     /**
253      * @return Returns the edgeLabelClosenessFunction.
254      */
255     public NumberEdgeValue getEdgeLabelClosenessFunction() {
2560        return edgeLabelClosenessFunction;
257     }
258  
259     /**
260      * @return Returns the edgePaintFunction.
261      */
262     public EdgePaintFunction getEdgePaintFunction() {
2630        return edgePaintFunction;
264     }
265  
266     /**
267      * @return Returns the edgeStringer.
268      */
269     public EdgeStringer getEdgeStringer() {
2700        return edgeStringer;
271     }
272  
273     /**
274      * @return Returns the edgeStrokeFunction.
275      */
276     public EdgeStrokeFunction getEdgeStrokeFunction() {
2770        return edgeStrokeFunction;
278     }
279  
280     /**
281      * @return Returns the screenDevice.
282      */
283     public JComponent getScreenDevice() {
2840        return screenDevice;
285     }
286  
287     /**
288      * @return Returns the vertexFontFunction.
289      */
290     public VertexFontFunction getVertexFontFunction() {
2910        return vertexFontFunction;
292     }
293  
294     /**
295      * @return Returns the vertexIncludePredicate.
296      */
297     public Predicate getVertexIncludePredicate() {
2980        return vertexIncludePredicate;
299     }
300  
301     /**
302      * @return Returns the vertexPaintFunction.
303      */
304     public VertexPaintFunction getVertexPaintFunction() {
3050        return vertexPaintFunction;
306     }
307  
308     /**
309      * @return Returns the vertexStringer.
310      */
311     public VertexStringer getVertexStringer() {
3120        return vertexStringer;
313     }
314  
315     /**
316      * @return Returns the vertexIconFunction
317      */
318     public VertexIconFunction getVertexIconFunction() {
3190        return vertexIconFunction;
320     }
321  
322     /**
323      * @param vertexIconFunction The VertexIconFunction to set.
324      */
325     public void setVertexIconFunction(VertexIconFunction vertexIconFunction) {
3260        this.vertexIconFunction = vertexIconFunction;
3270    }
328  
329     /**
330      * @return Returns the vertexStrokeFunction.
331      */
332     public VertexStrokeFunction getVertexStrokeFunction() {
3330        return vertexStrokeFunction;
334     }
335  
336     /**
337      * The screen device is the JComponent on which the renderer
338      * will display the graph. It is used here to assist with removing
339      * unnecessary calls to position and draw graph elements that will
340      * not be visible in the display. It is also used as the container
341      * for the CellRendererPane.
342      * @param screenDevice
343      */
344     public void setScreenDevice(JComponent screenDevice) {
3450        this.screenDevice = screenDevice;
3460        this.screenDevice.add(rendererPane);
3470    }
348     
349     /**
350      * Specifies the smallest (squared) distance that an arrowhead
351      * must be moved in order for the placement code to decide that
352      * it's "close enough". Default value is 1.
353      */
354     public void setArrowPlacementTolerance(float tolerance) {
3550        this.arrow_placement_tolerance = tolerance;
3560    }
357     
358     /**
359      * Sets the <code>EdgeArrowFunction</code> that specifies the
360      * <code>Shape</code> of the arrowheads for each edge.
361      * The same shape will be used for both ends of an undirected
362      * edge. The default arrow-drawing implementations assume that arrows
363      * are drawn with their base on the y-axis, pointed left (in the negative
364      * x-direction), centered on the x-axis.
365      * Note that the <code>EdgeArrowFunction</code> must return a valid shape
366      * for any edge for which the edge arrow <code>Predicate</code>
367      * returns <code>true</code>.
368      * <br>Default: wedge arrows for undirected edges, notched arrows for directed edges
369      * (<code>DirectionalEdgeArrowFunction</code>)
370      * @see edu.uci.ics.jung.decorators.EdgeArrowFunction
371      * @see ArrowFactory
372      */
373     public void setEdgeArrowFunction(EdgeArrowFunction eaf)
374     {
3750        this.edgeArrowFunction = eaf;
3760    }
377     
378     /**
379      * @return Returns the graphLabelRenderer.
380      */
381     public GraphLabelRenderer getGraphLabelRenderer() {
3820        return graphLabelRenderer;
383     }
384     /**
385      * @param graphLabelRenderer The graphLabelRenderer to set.
386      */
387     public void setGraphLabelRenderer(GraphLabelRenderer graphLabelRenderer) {
3880        this.graphLabelRenderer = graphLabelRenderer;
3890    }
390     /**
391      * Sets the <code>EdgeArrowPredicate</code> that specifies whether
392      * arrowheads should be drawn for each edge. If the predicate evaluates
393      * to <code>true</code> for a specified edge, arrows should be drawn
394      * for that edge.
395      * <br>Default: only directed edges have arrows (<code>Graph.DIRECTED_EDGE</code> instance)
396      * @see EdgeArrowFunction
397      */
398     public void setEdgeArrowPredicate(Predicate p)
399     {
4000        this.edgeArrowPredicate = p;
4010    }
402  
403     /**
404      * Sets the <code>EdgeColorFunction</code> that specifies the paint to
405      * draw each edge.
406      * <br>Default: Color.BLACK
407      * @see java.awt.Color
408      * @deprecated Use setEdgePaintFunction instead
409      */
410     public void setEdgeColorFunction(EdgeColorFunction ecf)
411     {
4120        this.edgePaintFunction = new EdgeColorToEdgePaintFunctionConverter( ecf );
4130    }
414  
415     
416     /**
417      * Sets the <code>EdgeFontFunction</code> that specifies the font
418      * to use for drawing each edge label. This can be used (for example) to
419      * emphasize (or to de-emphasize) edges that have a specific property.
420      * <br>Default: 12-point Helvetica
421      * @see EdgeFontFunction
422      */
423     public void setEdgeFontFunction(EdgeFontFunction eff)
424     {
4250        this.edgeFontFunction = eff;
4260    }
427     
428     /**
429      * Sets the <code>Predicate</code> that specifies whether each
430      * edge should be drawn; only those edges for which this
431      * predicate returns <code>true</code> will be drawn. This can be
432      * used to selectively display only those edges that have a
433      * specific property, such as a particular decoration or value, or
434      * only those edges of a specific type (such as directed edges,
435      * or everything except self-loops).
436      * <br>Default: all edges drawn (<code>TruePredicate</code> instance)
437      * @see org.apache.commons.collections.Predicate
438      */
439     public void setEdgeIncludePredicate(Predicate p)
440     {
4410        this.edgeIncludePredicate = p;
4420    }
443     
444     /**
445      * Sets the <code>NumberEdgeValue</code> that specifies where to draw
446      * the label for each edge. A value of 0 draws the label on top of
447      * the edge's first vertex; a value of 1.0 draws the label on top
448      * of the edge's second vertex; values between 0 and 1 split the
449      * difference (i.e., a value of 0.5 draws the label halfway in between
450      * the two vertices). The effect of values outside the range [0,1]
451      * is undefined. This function is not used for self-loops.
452      * <br>Default: 0.5 for undirected edges, 0.75 for directed edges
453      * (<code>ConstantDirectionalEdgeValue</code>)
454      * @see edu.uci.ics.jung.graph.decorators.NumberEdgeValue
455      */
456     public void setEdgeLabelClosenessFunction(NumberEdgeValue nev)
457     {
4580        this.edgeLabelClosenessFunction = nev;
4590    }
460  
461     /**
462      * @param impl
463      */
464     public void setEdgePaintFunction(EdgePaintFunction impl) {
4650        edgePaintFunction = impl;
466         
4670    }
468     
469     /**
470      * setter for the EdgeShapeFunction
471      * @param impl
472      */
473     public void setEdgeShapeFunction(EdgeShapeFunction impl) {
4740        edgeShapeFunction = impl;
4750        if(edgeShapeFunction instanceof EdgeShape.ParallelRendering) {
4760            ((EdgeShape.ParallelRendering)edgeShapeFunction).setParallelEdgeIndexFunction(this.parallelEdgeIndexFunction);
477         }
4780    }
479  
480     /**
481      * @return Returns the EdgeShapeFunction that .
482      */
483     public EdgeShapeFunction getEdgeShapeFunction() {
4840        return edgeShapeFunction;
485     }
486     /**
487      * Sets the <code>EdgeStringer</code> that specifies the label to
488      * draw for each edge.
489      * <br>Default: no labels
490      * (<code>ConstantEdgeStringer</code>)
491      * @see edu.uci.ics.jung.graph.decorators.EdgeStringer
492      */
493     public void setEdgeStringer(EdgeStringer es)
494     {
4950        this.edgeStringer = es;
4960    }
497     
498     /**
499      * Sets the <code>EdgeStrokeFunction</code> that specifies the
500      * <code>Stroke</code> to use when drawing each edge.
501      * <br>Default: 1-pixel-width basic stroke
502      * (<code>ConstantEdgeStrokeFunction</code>)
503      * @see java.awt.Stroke
504      * @see EdgeStrokeFunction
505      */
506     public void setEdgeStrokeFunction(EdgeStrokeFunction esf)
507     {
5080        this.edgeStrokeFunction = esf;
5090    }
510  
511     /**
512      * <p>Sets the <code>VertexPaintFunction</code> to the parameter
513      * @see #setVertexPaintFunction(VertexPaintFunction)
514      * @see VertexColorFunction
515      * @see VertexColorToVertexPaintConverter
516      * @deprecated Use setVertexPaintFunction with a VertexPaintFunction if you can
517      */
518     public void setVertexColorFunction(VertexColorFunction vcf)
519     {
5200        this.vertexPaintFunction = new VertexColorToVertexPaintConverter( vcf );
5210    }
522  
523     /**
524     * <p>Sets the <code>VertexPaintFunction</code> which specifies the
525     * draw (border and text) and fill (interior) Paint for each vertex.</p>
526     * <p>If users want the <code>VertexPaintFunction</code> implementation
527     * to highlight selected vertices, they should take this
528     * PluggableRenderer instance as a constructor parameter, and call
529     * the <code>isPicked</code> method on it to identify selected vertices.</p>
530     * <p>Default: black borders, red foreground (selected vertex is orange).</p>
531     */
532     public void setVertexPaintFunction( VertexPaintFunction vpf )
533     {
5340        this.vertexPaintFunction = vpf;
5350    }
536     
537     /**
538      * Returns the <code>VertexShapeFunction</code> currently being
539      * used by this instance.
540      */
541     public VertexShapeFunction getVertexShapeFunction()
542     {
5430        return vertexShapeFunction;
544     }
545     
546     /**
547      * Sets the <code>VertexFontFunction</code> that specifies the font
548      * to use for drawing each vertex label. This can be used (for example) to
549      * emphasize (or to de-emphasize) vertices that have a specific property.
550      * <br>Default: 12-point Helvetica
551      * @see VertexFontFunction
552      */
553     public void setVertexFontFunction(VertexFontFunction vff)
554     {
5550        this.vertexFontFunction = vff;
5560    }
557  
558     /**
559      * Sets the <code>Predicate</code> that specifies whether each
560      * vertex should be drawn; only those vertices for which this
561      * predicate returns <code>true</code> will be drawn. This can be
562      * used to selectively display only those vertices that have a
563      * specific property, such as a particular decoration or value.
564      * <br>Default: all vertices drawn (<code>TruePredicate</code> instance)
565      * @see org.apache.commons.collections.Predicate
566      */
567     public void setVertexIncludePredicate(Predicate p)
568     {
5690        this.vertexIncludePredicate = p;
5700    }
571     
572     /**
573      * Specifies whether vertex labels are drawn centered on the vertex
574      * position (<code>true</code>) or offset to one side (<code>false</code>).
575      * <br>Default: offset
576      */
577     public void setVertexLabelCentering(boolean b)
578     {
5790        centerVertexLabel = b;
5800    }
581     
582     /**
583      *
584      * @return whether the vertex labels should be centered in the vertex
585      */
586     public boolean getVertexLabelCentering()
587     {
5880        return centerVertexLabel;
589     }
590     
591     /**
592      * Sets the <code>VertexShapeFunction</code>,
593      * which specifies the <code>Shape</code> for each vertex.
594      * Users that wish to independently change the size and
595      * aspect ratio of a vertex's shape should take a look
596      * at the <code>SettableVertexShapeFunction</code>
597      * interface and the <code>AbstractVertexShapeFunction</code>
598      * abstract class.
599      * <br>Default: 8-pixel-diameter circle
600      * (<code>EllipseVertexShapeFunction</code>)
601      * @see java.awt.Shape
602      * @see VertexShapeFunction
603      */
604     public void setVertexShapeFunction(VertexShapeFunction vsf)
605     {
6060        this.vertexShapeFunction = vsf;
6070    }
608     
609     /**
610      * Sets the <code>VertexStringer</code> that specifies the label to
611      * draw for each vertex.
612      * <br>Default: no labels
613      * (<code>ConstantVertexStringer</code>)
614      * @see edu.uci.ics.jung.graph.decorators.VertexStringer
615      */
616     public void setVertexStringer(VertexStringer vs)
617     {
6180        this.vertexStringer = vs;
6190    }
620  
621     /**
622      * Sets the <code>VertexStrokeFunction</code> which
623      * specifies the <code>Stroke</code> to use when drawing
624      * each vertex border.
625      * <br>Default: 1-pixel-width basic stroke.
626      * @see java.awt.Stroke
627      * @see VertexStrokeFunction
628      */
629     public void setVertexStrokeFunction(VertexStrokeFunction vsf)
630     {
6310        this.vertexStrokeFunction = vsf;
6320    }
633         
634  
635     /**
636      * Paints <code>e</code>, whose endpoints are at <code>(x1,y1)</code>
637      * and <code>(x2,y2)</code>, on the graphics context <code>g</code>.
638      * Uses the paint and stroke specified by this instance's
639      * <code>EdgeColorFunction</code> and <code>EdgeStrokeFunction</code>,
640      * respectively. (If the paint is unspecified, the existing
641      * paint for the graphics context is used; the same applies to stroke.)
642      * The details of the actual rendering are delegated to
643      * <code>drawSelfLoop</code> or <code>drawSimpleEdge</code>,
644      * depending on the type of the edge.
645      * Note that <code>(x1, y1)</code> is the location of
646      * e.getEndpoints.getFirst() and <code>(x2, y2)</code> is the location of
647      * e.getEndpoints.getSecond().
648      *
649      */
650     public void paintEdge(Graphics g, Edge e, int x1, int y1, int x2, int y2)
651     {
6520        if (!edgeIncludePredicate.evaluate(e))
6530            return;
654         
655         // don't draw edge if either incident vertex is not drawn
6560        Pair endpoints = e.getEndpoints();
6570        Vertex v1 = (Vertex)endpoints.getFirst();
6580        Vertex v2 = (Vertex)endpoints.getSecond();
6590        if (!vertexIncludePredicate.evaluate(v1) ||
660             !vertexIncludePredicate.evaluate(v2))
6610            return;
662         
6630        Graphics2D g2d = (Graphics2D) g;
664  
6650        Stroke new_stroke = edgeStrokeFunction.getStroke(e);
6660        Stroke old_stroke = g2d.getStroke();
6670        if (new_stroke != null)
6680            g2d.setStroke(new_stroke);
669         
6700        drawSimpleEdge(g2d, e, x1, y1, x2, y2);
671  
672         // restore paint and stroke
6730        if (new_stroke != null)
6740            g2d.setStroke(old_stroke);
675  
6760    }
677  
678     /**
679      * Draws the edge <code>e</code>, whose endpoints are at <code>(x1,y1)</code>
680      * and <code>(x2,y2)</code>, on the graphics context <code>g</code>.
681      * The <code>Shape</code> provided by the <code>EdgeShapeFunction</code> instance
682      * is scaled in the x-direction so that its width is equal to the distance between
683      * <code>(x1,y1)</code> and <code>(x2,y2)</code>.
684      */
685     protected void drawSimpleEdge(Graphics2D g, Edge e, int x1, int y1, int x2, int y2)
686     {
6870        Pair endpoints = e.getEndpoints();
6880        Vertex v1 = (Vertex)endpoints.getFirst();
6890        Vertex v2 = (Vertex)endpoints.getSecond();
6900        boolean isLoop = v1.equals(v2);
6910        Shape s2 = vertexShapeFunction.getShape(v2);
6920        Shape edgeShape = edgeShapeFunction.getShape(e);
693         
6940        boolean edgeHit = true;
6950        boolean arrowHit = true;
6960        Rectangle deviceRectangle = null;
6970        if(screenDevice != null) {
6980            Dimension d = screenDevice.getSize();
6990            if(d.width <= 0 || d.height <= 0) {
7000                d = screenDevice.getPreferredSize();
701             }
7020            deviceRectangle = new Rectangle(0,0,d.width,d.height);
703         }
704  
7050        AffineTransform xform = AffineTransform.getTranslateInstance(x1, y1);
706         
7070        if(isLoop) {
708             // this is a self-loop. scale it is larger than the vertex
709             // it decorates and translate it so that its nadir is
710             // at the center of the vertex.
7110            Rectangle2D s2Bounds = s2.getBounds2D();
7120            xform.scale(s2Bounds.getWidth(),s2Bounds.getHeight());
7130            xform.translate(0, -edgeShape.getBounds2D().getWidth()/2);
714         } else {
715             // this is a normal edge. Rotate it to the angle between
716             // vertex endpoints, then scale it to the distance between
717             // the vertices
7180            float dx = x2-x1;
7190            float dy = y2-y1;
7200            float thetaRadians = (float) Math.atan2(dy, dx);
7210            xform.rotate(thetaRadians);
7220            float dist = (float) Math.sqrt(dx*dx + dy*dy);
7230            xform.scale(dist, 1.0);
724         }
725         
7260        edgeShape = xform.createTransformedShape(edgeShape);
727         
7280        edgeHit = viewTransformer.transform(edgeShape).intersects(deviceRectangle);
729  
7300        if(edgeHit == true) {
731             
7320            Paint oldPaint = g.getPaint();
733             
734             // get Paints for filling and drawing
735             // (filling is done first so that drawing and label use same Paint)
7360            Paint fill_paint = edgePaintFunction.getFillPaint(e);
7370            if (fill_paint != null)
738             {
7390                g.setPaint(fill_paint);
7400                g.fill(edgeShape);
741             }
7420            Paint draw_paint = edgePaintFunction.getDrawPaint(e);
7430            if (draw_paint != null)
744             {
7450                g.setPaint(draw_paint);
7460                g.draw(edgeShape);
747             }
748             
7490            float scalex = (float)g.getTransform().getScaleX();
7500            float scaley = (float)g.getTransform().getScaleY();
751             // see if arrows are too small to bother drawing
7520            if(scalex < .3 || scaley < .3) return;
753             
7540            if (edgeArrowPredicate.evaluate(e)) {
755                 
7560                Shape destVertexShape =
757                     vertexShapeFunction.getShape((Vertex)e.getEndpoints().getSecond());
7580                AffineTransform xf = AffineTransform.getTranslateInstance(x2, y2);
7590                destVertexShape = xf.createTransformedShape(destVertexShape);
760                 
7610                arrowHit = viewTransformer.transform(destVertexShape).intersects(deviceRectangle);
7620                if(arrowHit) {
763                     
764                     AffineTransform at;
7650                    if (edgeShape instanceof GeneralPath)
7660                        at = getArrowTransform((GeneralPath)edgeShape, destVertexShape);
767                     else
7680                        at = getArrowTransform(new GeneralPath(edgeShape), destVertexShape);
7690                    if(at == null) return;
7700                    Shape arrow = edgeArrowFunction.getArrow(e);
7710                    arrow = at.createTransformedShape(arrow);
772                     // note that arrows implicitly use the edge's draw paint
7730                    g.fill(arrow);
774                 }
7750                if (e instanceof UndirectedEdge) {
7760                    Shape vertexShape =
777                         vertexShapeFunction.getShape((Vertex)e.getEndpoints().getFirst());
7780                    xf = AffineTransform.getTranslateInstance(x1, y1);
7790                    vertexShape = xf.createTransformedShape(vertexShape);
780                     
7810                    arrowHit = viewTransformer.transform(vertexShape).intersects(deviceRectangle);
782                     
7830                    if(arrowHit) {
784                         AffineTransform at;
7850                        if (edgeShape instanceof GeneralPath)
7860                            at = getReverseArrowTransform((GeneralPath)edgeShape, vertexShape, !isLoop);
787                         else
7880                            at = getReverseArrowTransform(new GeneralPath(edgeShape), vertexShape, !isLoop);
7890                        if(at == null) return;
7900                        Shape arrow = edgeArrowFunction.getArrow(e);
7910                        arrow = at.createTransformedShape(arrow);
7920                        g.fill(arrow);
793                     }
794                 }
795             }
796             // use existing paint for text if no draw paint specified
7970            if (draw_paint == null)
7980                g.setPaint(oldPaint);
7990            String label = edgeStringer.getLabel(e);
8000            if (label != null) {
8010                labelEdge(g, e, label, x1, x2, y1, y2);
802             }
803             
804             
805             // restore old paint
8060            g.setPaint(oldPaint);
807         }
8080    }
809     
810     /**
811      * Returns a transform to position the arrowhead on this edge shape at the
812      * point where it intersects the passed vertex shape.
813      */
814     public AffineTransform getArrowTransform(GeneralPath edgeShape, Shape vertexShape) {
8150        float[] seg = new float[6];
8160        Point2D p1=null;
8170        Point2D p2=null;
8180        AffineTransform at = new AffineTransform();
819         // when the PathIterator is done, switch to the line-subdivide
820         // method to get the arrowhead closer.
8210        for(PathIterator i=edgeShape.getPathIterator(null,1); !i.isDone(); i.next()) {
8220            int ret = i.currentSegment(seg);
8230            if(ret == PathIterator.SEG_MOVETO) {
8240                p2 = new Point2D.Float(seg[0],seg[1]);
8250            } else if(ret == PathIterator.SEG_LINETO) {
8260                p1 = p2;
8270                p2 = new Point2D.Float(seg[0],seg[1]);
8280                if(vertexShape.contains(p2)) {
8290                    at = getArrowTransform(new Line2D.Float(p1,p2),vertexShape);
8300                    break;
831                 }
832             }
833         }
8340        return at;
835     }
836  
837     /**
838      * Returns a transform to position the arrowhead on this edge shape at the
839      * point where it intersects the passed vertex shape.
840      */
841     public AffineTransform getReverseArrowTransform(GeneralPath edgeShape, Shape vertexShape) {
8420        return getReverseArrowTransform(edgeShape, vertexShape, true);
843     }
844             
845     /**
846      * <p>Returns a transform to position the arrowhead on this edge shape at the
847      * point where it intersects the passed vertex shape.</p>
848      *
849      * <p>The Loop edge is a special case because its staring point is not inside
850      * the vertex. The passedGo flag handles this case.</p>
851      *
852      * @param edgeShape
853      * @param vertexShape
854      * @param passedGo - used only for Loop edges
855      */
856     public AffineTransform getReverseArrowTransform(GeneralPath edgeShape, Shape vertexShape,
857             boolean passedGo) {
8580        float[] seg = new float[6];
8590        Point2D p1=null;
8600        Point2D p2=null;
861  
8620        AffineTransform at = new AffineTransform();
8630        for(PathIterator i=edgeShape.getPathIterator(null,1); !i.isDone(); i.next()) {
8640            int ret = i.currentSegment(seg);
8650            if(ret == PathIterator.SEG_MOVETO) {
8660                p2 = new Point2D.Float(seg[0],seg[1]);
8670            } else if(ret == PathIterator.SEG_LINETO) {
8680                p1 = p2;
8690                p2 = new Point2D.Float(seg[0],seg[1]);
8700                if(passedGo == false && vertexShape.contains(p2)) {
8710                    passedGo = true;
8720                 } else if(passedGo==true &&
873                         vertexShape.contains(p2)==false) {
8740                     at = getReverseArrowTransform(new Line2D.Float(p1,p2),vertexShape);
8750                    break;
876                 }
877             }
878         }
8790        return at;
880     }
881  
882     /**
883      * This is used for the arrow of a directed and for one of the
884      * arrows for non-directed edges
885      * Get a transform to place the arrow shape on the passed edge at the
886      * point where it intersects the passed shape
887      * @param edgeShape
888      * @param vertexShape
889      * @return
890      */
891     public AffineTransform getArrowTransform(Line2D edgeShape, Shape vertexShape) {
8920        float dx = (float) (edgeShape.getX1()-edgeShape.getX2());
8930        float dy = (float) (edgeShape.getY1()-edgeShape.getY2());
894         // iterate over the line until the edge shape will place the
895         // arrowhead closer than 'arrowGap' to the vertex shape boundary
8960        while((dx*dx+dy*dy) > arrow_placement_tolerance) {
897             try {
8980                edgeShape = getLastOutsideSegment(edgeShape, vertexShape);
8990            } catch(IllegalArgumentException e) {
9000                System.err.println(e.toString());
9010                return null;
9020            }
9030            dx = (float) (edgeShape.getX1()-edgeShape.getX2());
9040            dy = (float) (edgeShape.getY1()-edgeShape.getY2());
905         }
9060        double atheta = Math.atan2(dx,dy)+Math.PI/2;
9070        AffineTransform at =
908             AffineTransform.getTranslateInstance(edgeShape.getX1(), edgeShape.getY1());
9090        at.rotate(-atheta);
9100        return at;
911     }
912  
913     /**
914      * This is used for the reverse-arrow of a non-directed edge
915      * get a transform to place the arrow shape on the passed edge at the
916      * point where it intersects the passed shape
917      * @param edgeShape
918      * @param vertexShape
919      * @return
920      */
921     protected AffineTransform getReverseArrowTransform(Line2D edgeShape, Shape vertexShape) {
9220        float dx = (float) (edgeShape.getX1()-edgeShape.getX2());
9230        float dy = (float) (edgeShape.getY1()-edgeShape.getY2());
924         // iterate over the line until the edge shape will place the
925         // arrowhead closer than 'arrowGap' to the vertex shape boundary
9260        while((dx*dx+dy*dy) > arrow_placement_tolerance) {
927             try {
9280                edgeShape = getFirstOutsideSegment(edgeShape, vertexShape);
9290            } catch(IllegalArgumentException e) {
9300                System.err.println(e.toString());
9310                return null;
9320            }
9330            dx = (float) (edgeShape.getX1()-edgeShape.getX2());
9340            dy = (float) (edgeShape.getY1()-edgeShape.getY2());
935         }
936         // calculate the angle for the arrowhead
9370        double atheta = Math.atan2(dx,dy)-Math.PI/2;
9380        AffineTransform at = AffineTransform.getTranslateInstance(edgeShape.getX1(),edgeShape.getY1());
9390        at.rotate(-atheta);
9400        return at;
941     }
942     
943     /**
944      * Passed Line's point2 must be inside the passed shape or
945      * an IllegalArgumentException is thrown
946      * @param line line to subdivide
947      * @param shape shape to compare with line
948      * @return a line that intersects the shape boundary
949      * @throws IllegalArgumentException if the passed line's point1 is not inside the shape
950      */
951     protected Line2D getLastOutsideSegment(Line2D line, Shape shape) {
9520        if(shape.contains(line.getP2())==false) {
9530            String errorString =
954                 "line end point: "+line.getP2()+" is not contained in shape: "+shape.getBounds2D();
9550            throw new IllegalArgumentException(errorString);
956             //return null;
957         }
9580        Line2D left = new Line2D.Double();
9590        Line2D right = new Line2D.Double();
960         // subdivide the line until its left segment intersects
961         // the shape boundary
9620        int iterations = 0;
963         do {
9640            subdivide(line, left, right);
9650            line = right;
9660        } while(shape.contains(line.getP1())==false && iterations++ < MAX_ITERATIONS);
967         // now that right is completely inside shape,
968         // return left, which must be partially outside
9690        return left;
970     }
971    
972     /**
973      * Passed Line's point1 must be inside the passed shape or
974      * an IllegalArgumentException is thrown
975      * @param line line to subdivide
976      * @param shape shape to compare with line
977      * @return a line that intersects the shape boundary
978      * @throws IllegalArgumentException if the passed line's point1 is not inside the shape
979      */
980     protected Line2D getFirstOutsideSegment(Line2D line, Shape shape) {
981         
9820        if(shape.contains(line.getP1())==false) {
9830            String errorString =
984                 "line start point: "+line.getP1()+" is not contained in shape: "+shape.getBounds2D();
9850            throw new IllegalArgumentException(errorString);
986         }
9870        Line2D left = new Line2D.Float();
9880        Line2D right = new Line2D.Float();
989         // subdivide the line until its right side intersects the
990         // shape boundary
991         do {
9920            subdivide(line, left, right);
9930            line = left;
9940        } while(shape.contains(line.getP2())==false);
995         // now that left is completely inside shape,
996         // return right, which must be partially outside
9970        return right;
998     }
999  
1000     /**
1001      * divide a Line2D into 2 new Line2Ds that are returned
1002      * in the passed left and right instances, if non-null
1003      * @param src the line to divide
1004      * @param left the left side, or null
1005      * @param right the right side, or null
1006      */
1007     protected void subdivide(Line2D src,
1008             Line2D left,
1009             Line2D right) {
10100        double x1 = src.getX1();
10110        double y1 = src.getY1();
10120        double x2 = src.getX2();
10130        double y2 = src.getY2();
1014         
10150        double mx = x1 + (x2-x1)/2.0;
10160        double my = y1 + (y2-y1)/2.0;
10170        if (left != null) {
10180            left.setLine(x1, y1, mx, my);
1019         }
10200        if (right != null) {
10210            right.setLine(mx, my, x2, y2);
1022         }
10230    }
1024  
1025    public Component prepareRenderer(GraphLabelRenderer graphLabelRenderer, Object value,
1026            boolean isSelected, Vertex vertex) {
10270       return graphLabelRenderer.getGraphLabelRendererComponent(screenDevice, value,
1028                vertexFontFunction.getFont(vertex), isSelected, vertex);
1029    }
1030  
1031    public Component prepareRenderer(GraphLabelRenderer renderer, Object value,
1032            boolean isSelected, Edge edge) {
10330       return graphLabelRenderer.getGraphLabelRendererComponent(screenDevice, value,
1034                edgeFontFunction.getFont(edge), isSelected, edge);
1035    }
1036  
1037     /**
1038      * Labels the specified non-self-loop edge with the specified label.
1039      * Uses the font specified by this instance's
1040      * <code>EdgeFontFunction</code>. (If the font is unspecified, the existing
1041      * font for the graphics context is used.) Positions the
1042      * label between the endpoints according to the coefficient returned
1043      * by this instance's edge label closeness function.
1044      */
1045     protected void labelEdge(Graphics2D g2d, Edge e, String label, int x1, int x2, int y1, int y2)
1046     {
10470        int distX = x2 - x1;
10480        int distY = y2 - y1;
10490        double totalLength = Math.sqrt(distX * distX + distY * distY);
1050  
10510        double closeness = edgeLabelClosenessFunction.getNumber(e).doubleValue();
1052  
10530        int posX = (int) (x1 + (closeness) * distX);
10540        int posY = (int) (y1 + (closeness) * distY);
1055  
10560        int xDisplacement = (int) (LABEL_OFFSET * (distY / totalLength));
10570        int yDisplacement = (int) (LABEL_OFFSET * (-distX / totalLength));
1058         
10590        Component component = prepareRenderer(graphLabelRenderer, label, isPicked(e), e);
1060         
10610        Dimension d = component.getPreferredSize();
1062  
10630        Shape edgeShape = edgeShapeFunction.getShape(e);
1064         
10650        double parallelOffset = 1;
1066  
10670        parallelOffset += parallelEdgeIndexFunction.getIndex(e);
1068  
10690        if(edgeShape instanceof Ellipse2D) {
10700            parallelOffset += edgeShape.getBounds().getHeight();
10710            parallelOffset = -parallelOffset;
1072         }
1073         
10740        parallelOffset *= d.height;
1075         
10760        AffineTransform old = g2d.getTransform();
10770        AffineTransform xform = new AffineTransform(old);
10780        xform.translate(posX+xDisplacement, posY+yDisplacement);
10790        double dx = x2 - x1;
10800        double dy = y2 - y1;
10810        if(graphLabelRenderer.isRotateEdgeLabels()) {
10820            double theta = Math.atan2(dy, dx);
10830            if(dx < 0) {
10840                theta += Math.PI;
1085             }
10860            xform.rotate(theta);
1087         }
10880        if(dx < 0) {
10890            parallelOffset = -parallelOffset;
1090         }
1091         
10920        xform.translate(-d.width/2, -(d.height/2-parallelOffset));
10930        g2d.setTransform(xform);
10940        rendererPane.paintComponent(g2d, component, screenDevice,
1095                 0, 0,
1096                 d.width, d.height, true);
10970        g2d.setTransform(old);
10980    }
1099  
1100     /**
1101      * Paints the vertex <code>v</code> at the location <code>(x,y)</code>
1102      * on the graphics context <code>g_gen</code>. The vertex is painted
1103      * using the shape returned by this instance's <code>VertexShapeFunction</code>,
1104      * and the foreground and background (border) colors provided by this
1105      * instance's <code>VertexColorFunction</code>. Delegates drawing the
1106      * label (if any) for this vertex to <code>labelVertex</code>.
1107      */
1108     public void paintVertex(Graphics g, Vertex v, int x, int y)
1109     {
11100        if (!vertexIncludePredicate.evaluate(v))
11110            return;
1112         
11130        boolean vertexHit = true;
11140        Rectangle deviceRectangle = null;
11150        Graphics2D g2d = (Graphics2D)g;
11160        if(screenDevice != null) {
11170            Dimension d = screenDevice.getSize();
11180            if(d.width <= 0 || d.height <= 0) {
11190                d = screenDevice.getPreferredSize();
1120             }
11210            deviceRectangle = new Rectangle(
1122                     0,0,
1123                     d.width,d.height);
1124         }
1125         
1126         
11270        Stroke old_stroke = g2d.getStroke();
11280        Stroke new_stroke = vertexStrokeFunction.getStroke(v);
11290        if (new_stroke != null) {
11300            g2d.setStroke(new_stroke);
1131         }
1132         // get the shape to be rendered
11330        Shape s = vertexShapeFunction.getShape(v);
1134         
1135         // create a transform that translates to the location of
1136         // the vertex to be rendered
11370        AffineTransform xform = AffineTransform.getTranslateInstance(x,y);
1138         // transform the vertex shape with xtransform
11390        s = xform.createTransformedShape(s);
1140         
11410        vertexHit = viewTransformer.transform(s).intersects(deviceRectangle);
1142  
11430        if (vertexHit) {
1144  
11450            if (vertexIconFunction != null) {
11460                paintIconForVertex(g2d, v, x, y);
1147             } else {
11480                paintShapeForVertex(g2d, v, s);
1149             }
1150  
11510            if (new_stroke != null) {
11520                g2d.setStroke(old_stroke);
1153             }
11540            String label = vertexStringer.getLabel(v);
11550            if (label != null) {
11560                labelVertex(g, v, label, x, y);
1157             }
1158         }
11590    }
1160     
1161     public void paintShapeForVertex(Graphics2D g2d, Vertex v, Shape shape) {
11620        Paint oldPaint = g2d.getPaint();
11630        Paint fillPaint = vertexPaintFunction.getFillPaint(v);
11640        if(fillPaint != null) {
11650            g2d.setPaint(fillPaint);
11660            g2d.fill(shape);
11670            g2d.setPaint(oldPaint);
1168         }
11690        Paint drawPaint = vertexPaintFunction.getDrawPaint(v);
11700        if(drawPaint != null) {
11710            g2d.setPaint(drawPaint);
11720            g2d.draw(shape);
11730            g2d.setPaint(oldPaint);
1174         }
11750    }
1176     
1177     /**
1178      * Paint <code>v</code>'s icon on <code>g</code> at <code>(x,y)</code>.
1179      */
1180     public void paintIconForVertex(Graphics g, Vertex v, int x, int y) {
11810        Icon icon = vertexIconFunction.getIcon(v);
11820        if(icon == null) {
11830            Shape s = AffineTransform.getTranslateInstance(x,y).
1184                 createTransformedShape(getVertexShapeFunction().getShape(v));
11850            paintShapeForVertex((Graphics2D)g, v, s);
1186         } else {
11870            int xLoc = x - icon.getIconWidth()/2;
11880            int yLoc = y - icon.getIconHeight()/2;
11890            icon.paintIcon(screenDevice, g, xLoc, yLoc);
1190         }
11910    }
1192     
1193     /**
1194      * Labels the specified vertex with the specified label.
1195      * Uses the font specified by this instance's
1196      * <code>VertexFontFunction</code>. (If the font is unspecified, the existing
1197      * font for the graphics context is used.) If vertex label centering
1198      * is active, the label is centered on the position of the vertex; otherwise
1199      * the label is offset slightly.
1200      */
1201     protected void labelVertex(Graphics g, Vertex v, String label, int x, int y)
1202     {
12030        Component component = prepareRenderer(graphLabelRenderer, label, isPicked(v), v);
1204  
12050        Dimension d = component.getPreferredSize();
1206         
1207         int h_offset;
1208         int v_offset;
12090        if (centerVertexLabel)
1210         {
12110            h_offset = -d.width / 2;
12120            v_offset = -d.height / 2;
1213  
1214         }
1215         else
1216         {
12170            Rectangle2D bounds = vertexShapeFunction.getShape(v).getBounds2D();
12180            h_offset = (int)(bounds.getWidth() / 2) + 5;
12190            v_offset = (int)(bounds.getHeight() / 2) + 5 -d.height;
1220         }
1221         
12220        rendererPane.paintComponent(g, component, screenDevice, x+h_offset, y+v_offset,
1223                 d.width, d.height, true);
1224         
12250    }
1226     
1227     /**
1228      * @see AbstractRenderer#isPicked(Vertex)
1229      * @deprecated Use an independent PickedInfo instead of this version,
1230      * which relies on the Renderer to supply an instance.
1231      */
1232     public boolean isPicked(ArchetypeVertex v)
1233     {
12340        return super.isPicked(v);
1235     }
1236     
1237     /**
1238      * @see AbstractRenderer#isPicked(Edge)
1239      * @deprecated Use an independent PickedInfo instead of this version,
1240      * which relies on the Renderer to supply an instance.
1241      */
1242     public boolean isPicked(ArchetypeEdge e) {
12430        return super.isPicked(e);
1244     }
1245  
1246     /**
1247      * @return Returns the rendererPane.
1248      */
1249     public CellRendererPane getRendererPane() {
12500        return rendererPane;
1251     }
1252  
1253     /**
1254      * @param rendererPane The rendererPane to set.
1255      */
1256     public void setRendererPane(CellRendererPane rendererPane) {
12570        this.rendererPane = rendererPane;
12580    }
1259  
1260     public ParallelEdgeIndexFunction getParallelEdgeIndexFunction() {
12610        return parallelEdgeIndexFunction;
1262     }
1263  
1264     public void setParallelEdgeIndexFunction(
1265             ParallelEdgeIndexFunction parallelEdgeIndexFunction) {
12660        this.parallelEdgeIndexFunction = parallelEdgeIndexFunction;
12670    }
1268  
1269     public void setViewTransformer(MutableTransformer viewTransformer) {
12700        this.viewTransformer = viewTransformer;
12710    }
1272 }

this report was generated by version 1.0.5 of jcoverage.
visit www.jcoverage.com for updates.

copyright © 2003, jcoverage ltd. all rights reserved.
Java is a trademark of Sun Microsystems, Inc. in the United States and other countries.