001: package prefuse.util;
002:
003: import java.awt.BasicStroke;
004:
005: import prefuse.util.collections.IntObjectHashMap;
006:
007: /**
008: * Library maintaining a cache of drawing strokes and other useful stroke
009: * computation routines.
010: *
011: * @author <a href="http://jheer.org">jeffrey heer</a>
012: */
013: public class StrokeLib {
014:
015: private static final IntObjectHashMap strokeMap = new IntObjectHashMap();
016: private static int misses = 0;
017: private static int lookups = 0;
018:
019: /** Dash pattern for a dotted line */
020: public static final float[] DOTS = new float[] { 1.0f, 2.0f };
021: /** Dash pattern for regular uniform dashes */
022: public static final float[] DASHES = new float[] { 5.0f, 5.0f };
023: /** Dash pattern for longer uniform dashes */
024: public static final float[] LONG_DASHES = new float[] { 10.0f,
025: 10.0f };
026:
027: /**
028: * Get a square capped, miter joined, non-dashed stroke of the given width.
029: * @param width the requested stroke width
030: * @return the stroke
031: */
032: public static BasicStroke getStroke(float width) {
033: return getStroke(width, BasicStroke.CAP_SQUARE,
034: BasicStroke.JOIN_MITER);
035: }
036:
037: /**
038: * Get a square capped, miter joined, dashed stroke with the given width
039: * and dashing attributes.
040: * @param width the requested stroke width
041: * @param dashes an array describing the alternation pattern of
042: * a dashed line. For example [5f, 3f] will create dashes of length 5
043: * with spaces of length 3 between them. A null value indicates no
044: * dashing.
045: * @return the stroke
046: * @see java.awt.BasicStroke
047: */
048: public static BasicStroke getStroke(float width, float[] dashes) {
049: return getStroke(width, BasicStroke.CAP_SQUARE,
050: BasicStroke.JOIN_MITER, 10.0f, dashes, 0f);
051: }
052:
053: /**
054: * Get a non-dashed stroke of the given width, cap, and join
055: * @param width the requested stroke width
056: * @param cap the requested cap type, one of
057: * {@link java.awt.BasicStroke#CAP_BUTT},
058: * {@link java.awt.BasicStroke#CAP_ROUND}, or
059: * {@link java.awt.BasicStroke#CAP_SQUARE}
060: * @param join the requested join type, one of
061: * {@link java.awt.BasicStroke#JOIN_BEVEL},
062: * {@link java.awt.BasicStroke#JOIN_MITER}, or
063: * {@link java.awt.BasicStroke#JOIN_ROUND}
064: * @return the stroke
065: */
066: public static BasicStroke getStroke(float width, int cap, int join) {
067: return getStroke(width, cap, join, 10.0f, null, 0f);
068: }
069:
070: /**
071: * Get a dashed stroke of the given width, cap, join, miter limit,
072: * and dashing attributes.
073: * @param width the requested stroke width
074: * @param cap the requested cap type, one of
075: * {@link java.awt.BasicStroke#CAP_BUTT},
076: * {@link java.awt.BasicStroke#CAP_ROUND}, or
077: * {@link java.awt.BasicStroke#CAP_SQUARE}
078: * @param join the requested join type, one of
079: * {@link java.awt.BasicStroke#JOIN_BEVEL},
080: * {@link java.awt.BasicStroke#JOIN_MITER}, or
081: * {@link java.awt.BasicStroke#JOIN_ROUND}
082: * @param miterLimit the miter limit at which to bevel miter joins
083: * @param dashes an array describing the alternation pattern of
084: * a dashed line. For example [5f, 3f] will create dashes of length 5
085: * with spaces of length 3 between them. A null value indicates no
086: * dashing.
087: * @param dashPhase the phase or offset from which to begin the
088: * dash pattern
089: * @return the stroke
090: * @see java.awt.BasicStroke
091: */
092: public static BasicStroke getStroke(float width, int cap, int join,
093: float miterLimit, float[] dashes, float dashPhase) {
094: int key = getStrokeKey(width, cap, join, miterLimit, dashes,
095: dashPhase);
096: BasicStroke s = null;
097: if ((s = (BasicStroke) strokeMap.get(key)) == null) {
098: s = new BasicStroke(width, cap, join, miterLimit, dashes,
099: dashPhase);
100: strokeMap.put(key, s);
101: ++misses;
102: }
103: ++lookups;
104: return s;
105: }
106:
107: /**
108: * Compute a hash-key for stroke storage and lookup.
109: */
110: protected static int getStrokeKey(float width, int cap, int join,
111: float miterLimit, float[] dashes, float dashPhase) {
112: int hash = Float.floatToIntBits(width);
113: hash = hash * 31 + join;
114: hash = hash * 31 + cap;
115: hash = hash * 31 + Float.floatToIntBits(miterLimit);
116: if (dashes != null) {
117: hash = hash * 31 + Float.floatToIntBits(dashPhase);
118: for (int i = 0; i < dashes.length; i++) {
119: hash = hash * 31 + Float.floatToIntBits(dashes[i]);
120: }
121: }
122: return hash;
123: }
124:
125: /**
126: * Get a stroke with the same properties as the given stroke, but with
127: * a modified width value.
128: * @param s the stroke to base the returned stroke on
129: * @param width the desired width of the derived stroke
130: * @return the derived Stroke
131: */
132: public static BasicStroke getDerivedStroke(BasicStroke s,
133: float width) {
134: if (s.getLineWidth() == width) {
135: return s;
136: } else {
137: return getStroke(width * s.getLineWidth(), s.getEndCap(), s
138: .getLineJoin(), s.getMiterLimit(),
139: s.getDashArray(), s.getDashPhase());
140: }
141: }
142:
143: /**
144: * Get the number of cache misses to the Stroke object cache.
145: * @return the number of cache misses
146: */
147: public static int getCacheMissCount() {
148: return misses;
149: }
150:
151: /**
152: * Get the number of cache lookups to the Stroke object cache.
153: * @return the number of cache lookups
154: */
155: public static int getCacheLookupCount() {
156: return lookups;
157: }
158:
159: /**
160: * Clear the Stroke object cache.
161: */
162: public static void clearCache() {
163: strokeMap.clear();
164: }
165:
166: } // end of class StrokeLib
|