Line | Hits | Source |
---|---|---|
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 | * Created on Jul 20, 2004 | |
9 | */ | |
10 | package edu.uci.ics.jung.visualization; | |
11 | ||
12 | import java.awt.Shape; | |
13 | import java.awt.geom.AffineTransform; | |
14 | import java.awt.geom.Ellipse2D; | |
15 | import java.awt.geom.GeneralPath; | |
16 | import java.awt.geom.Point2D; | |
17 | import java.awt.geom.Rectangle2D; | |
18 | import java.awt.geom.RoundRectangle2D; | |
19 | ||
20 | import edu.uci.ics.jung.graph.Vertex; | |
21 | import edu.uci.ics.jung.graph.decorators.ConstantVertexAspectRatioFunction; | |
22 | import edu.uci.ics.jung.graph.decorators.ConstantVertexSizeFunction; | |
23 | import edu.uci.ics.jung.graph.decorators.VertexAspectRatioFunction; | |
24 | import edu.uci.ics.jung.graph.decorators.VertexSizeFunction; | |
25 | ||
26 | /** | |
27 | * A utility class for generating <code>Shape</code>s for drawing vertices. | |
28 | * The available shapes include rectangles, rounded rectangles, ellipses, | |
29 | * regular polygons, and regular stars. The dimensions of the requested | |
30 | * shapes are defined by the specified <code>VertexSizeFunction</code> | |
31 | * and <code>VertexAspectRatioFunction</code> implementations: the width | |
32 | * of the bounding box of the shape is given by the vertex size, and the | |
33 | * height is given by the size multiplied by the vertex's aspect ratio. | |
34 | * | |
35 | * @author Joshua O'Madadhain | |
36 | */ | |
37 | public class VertexShapeFactory | |
38 | { | |
39 | protected VertexSizeFunction vsf; | |
40 | protected VertexAspectRatioFunction varf; | |
41 | ||
42 | /** | |
43 | * Creates a <code>VertexShapeFactory</code> with the specified | |
44 | * vertex size and aspect ratio functions. | |
45 | */ | |
46 | public VertexShapeFactory(VertexSizeFunction vsf, VertexAspectRatioFunction varf) | |
47 | 0 | { |
48 | 0 | this.vsf = vsf; |
49 | 0 | this.varf = varf; |
50 | 0 | } |
51 | ||
52 | /** | |
53 | * Creates a <code>VertexShapeFactory</code> with a constant size of | |
54 | * 10 and a constant aspect ratio of 1. | |
55 | */ | |
56 | public VertexShapeFactory() | |
57 | { | |
58 | 0 | this(new ConstantVertexSizeFunction(10), |
59 | new ConstantVertexAspectRatioFunction(1.0f)); | |
60 | 0 | } |
61 | ||
62 | 0 | private static final Rectangle2D theRectangle = new Rectangle2D.Float(); |
63 | /** | |
64 | * Returns a <code>Rectangle2D</code> whose width and | |
65 | * height are defined by this instance's size and | |
66 | * aspect ratio functions for this vertex. | |
67 | */ | |
68 | public Rectangle2D getRectangle(Vertex v) | |
69 | { | |
70 | 0 | float width = vsf.getSize(v); |
71 | 0 | float height = width * varf.getAspectRatio(v); |
72 | 0 | float h_offset = -(width / 2); |
73 | 0 | float v_offset = -(height / 2); |
74 | 0 | theRectangle.setFrame(h_offset, v_offset, width, height); |
75 | 0 | return theRectangle; |
76 | } | |
77 | ||
78 | 0 | private static final Ellipse2D theEllipse = new Ellipse2D.Float(); |
79 | /** | |
80 | * Returns a <code>Ellipse2D</code> whose width and | |
81 | * height are defined by this instance's size and | |
82 | * aspect ratio functions for this vertex. | |
83 | */ | |
84 | public Ellipse2D getEllipse(Vertex v) | |
85 | { | |
86 | 0 | theEllipse.setFrame(getRectangle(v)); |
87 | 0 | return theEllipse; |
88 | } | |
89 | ||
90 | 0 | private static final RoundRectangle2D theRoundRectangle = |
91 | new RoundRectangle2D.Float(); | |
92 | /** | |
93 | * Returns a <code>RoundRectangle2D</code> whose width and | |
94 | * height are defined by this instance's size and | |
95 | * aspect ratio functions for this vertex. The arc size is | |
96 | * set to be half the minimum of the height and width of the frame. | |
97 | */ | |
98 | public RoundRectangle2D getRoundRectangle(Vertex v) | |
99 | { | |
100 | 0 | Rectangle2D frame = getRectangle(v); |
101 | 0 | float arc_size = (float)Math.min(frame.getHeight(), frame.getWidth()) / 2; |
102 | 0 | theRoundRectangle.setRoundRect(frame.getX(), frame.getY(), |
103 | frame.getWidth(), frame.getHeight(), arc_size, arc_size); | |
104 | 0 | return theRoundRectangle; |
105 | } | |
106 | ||
107 | 0 | private static final GeneralPath thePolygon = new GeneralPath(); |
108 | /** | |
109 | * Returns a regular <code>num_sides</code>-sided | |
110 | * <code>Polygon</code> whose bounding | |
111 | * box's width and height are defined by this instance's size and | |
112 | * aspect ratio functions for this vertex. | |
113 | * @param num_sides the number of sides of the polygon; must be >= 3. | |
114 | */ | |
115 | public Shape getRegularPolygon(Vertex v, int num_sides) | |
116 | { | |
117 | 0 | if (num_sides < 3) |
118 | 0 | throw new IllegalArgumentException("Number of sides must be >= 3"); |
119 | 0 | Rectangle2D frame = getRectangle(v); |
120 | 0 | float width = (float)frame.getWidth(); |
121 | 0 | float height = (float)frame.getHeight(); |
122 | ||
123 | // generate coordinates | |
124 | 0 | double angle = 0; |
125 | 0 | thePolygon.reset(); |
126 | 0 | thePolygon.moveTo(0,0); |
127 | 0 | thePolygon.lineTo(width, 0); |
128 | 0 | double theta = (2 * Math.PI) / num_sides; |
129 | 0 | for (int i = 2; i < num_sides; i++) |
130 | { | |
131 | 0 | angle -= theta; |
132 | 0 | float delta_x = (float) (width * Math.cos(angle)); |
133 | 0 | float delta_y = (float) (width * Math.sin(angle)); |
134 | 0 | Point2D prev = thePolygon.getCurrentPoint(); |
135 | 0 | thePolygon.lineTo((float)prev.getX() + delta_x, (float)prev.getY() + delta_y); |
136 | } | |
137 | 0 | thePolygon.closePath(); |
138 | ||
139 | // scale polygon to be right size, translate to center at (0,0) | |
140 | 0 | Rectangle2D r = thePolygon.getBounds2D(); |
141 | 0 | double scale_x = width / r.getWidth(); |
142 | 0 | double scale_y = height / r.getHeight(); |
143 | ||
144 | 0 | AffineTransform at = AffineTransform.getTranslateInstance(-width/2, height/2); |
145 | 0 | at.scale(scale_x, scale_y); |
146 | ||
147 | 0 | Shape shape = at.createTransformedShape(thePolygon); |
148 | 0 | return shape; |
149 | } | |
150 | ||
151 | /** | |
152 | * Returns a regular <code>Polygon</code> of <code>num_points</code> | |
153 | * points whose bounding | |
154 | * box's width and height are defined by this instance's size and | |
155 | * aspect ratio functions for this vertex. | |
156 | * @param num_points the number of points of the polygon; must be >= 5. | |
157 | */ | |
158 | public Shape getRegularStar(Vertex v, int num_points) | |
159 | { | |
160 | 0 | if (num_points < 5) |
161 | 0 | throw new IllegalArgumentException("Number of sides must be >= 5"); |
162 | 0 | Rectangle2D frame = getRectangle(v); |
163 | 0 | float width = (float) frame.getWidth(); |
164 | 0 | float height = (float) frame.getHeight(); |
165 | ||
166 | // generate coordinates | |
167 | 0 | double theta = (2 * Math.PI) / num_points; |
168 | 0 | double angle = -theta/2; |
169 | 0 | thePolygon.reset(); |
170 | 0 | thePolygon.moveTo(0,0); |
171 | 0 | float delta_x = width * (float)Math.cos(angle); |
172 | 0 | float delta_y = width * (float)Math.sin(angle); |
173 | 0 | Point2D prev = thePolygon.getCurrentPoint(); |
174 | 0 | thePolygon.lineTo((float)prev.getX() + delta_x, (float)prev.getY() + delta_y); |
175 | 0 | for (int i = 1; i < num_points; i++) |
176 | { | |
177 | 0 | angle += theta; |
178 | 0 | delta_x = width * (float)Math.cos(angle); |
179 | 0 | delta_y = width * (float)Math.sin(angle); |
180 | 0 | prev = thePolygon.getCurrentPoint(); |
181 | 0 | thePolygon.lineTo((float)prev.getX() + delta_x, (float)prev.getY() + delta_y); |
182 | 0 | angle -= theta*2; |
183 | 0 | delta_x = width * (float)Math.cos(angle); |
184 | 0 | delta_y = width * (float)Math.sin(angle); |
185 | 0 | prev = thePolygon.getCurrentPoint(); |
186 | 0 | thePolygon.lineTo((float)prev.getX() + delta_x, (float)prev.getY() + delta_y); |
187 | } | |
188 | 0 | thePolygon.closePath(); |
189 | ||
190 | // scale polygon to be right size, translate to center at (0,0) | |
191 | 0 | Rectangle2D r = thePolygon.getBounds2D(); |
192 | 0 | double scale_x = width / r.getWidth(); |
193 | 0 | double scale_y = height / r.getHeight(); |
194 | ||
195 | 0 | float translationX = (float) (r.getMinX() + r.getWidth()/2); |
196 | 0 | float translationY = (float) (r.getMinY() + r.getHeight()/2); |
197 | ||
198 | 0 | AffineTransform at = AffineTransform.getScaleInstance(scale_x, scale_y); |
199 | 0 | at.translate(-translationX, -translationY); |
200 | ||
201 | 0 | Shape shape = at.createTransformedShape(thePolygon); |
202 | 0 | return shape; |
203 | } | |
204 | } |
this report was generated by version 1.0.5 of jcoverage. |
copyright © 2003, jcoverage ltd. all rights reserved. |