ruby_wordcram 1.0.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.mvn/extensions.xml +8 -0
  4. data/.mvn/wrapper/maven-wrapper.properties +1 -0
  5. data/Rakefile +28 -5
  6. data/docs/_posts/2017-03-07-getting_started.md +3 -2
  7. data/docs/_posts/2017-03-07-under_the_hood.md +33 -0
  8. data/lib/WordCram.jar +0 -0
  9. data/lib/jsoup-1.10.2.jar +0 -0
  10. data/lib/ruby_wordcram/version.rb +1 -1
  11. data/lib/ruby_wordcram.rb +1 -2
  12. data/pom.rb +53 -0
  13. data/pom.xml +87 -0
  14. data/ruby_wordcram.gemspec +1 -2
  15. data/src/cue/lang/Counter.java +141 -0
  16. data/src/cue/lang/IterableText.java +10 -0
  17. data/src/cue/lang/NGramIterator.java +151 -0
  18. data/src/cue/lang/SentenceIterator.java +86 -0
  19. data/src/cue/lang/WordIterator.java +60 -0
  20. data/src/cue/lang/stop/StopWords.java +114 -0
  21. data/src/cue/lang/stop/arabic +351 -0
  22. data/src/cue/lang/stop/armenian +45 -0
  23. data/src/cue/lang/stop/catalan +219 -0
  24. data/src/cue/lang/stop/croatian +2024 -0
  25. data/src/cue/lang/stop/czech +256 -0
  26. data/src/cue/lang/stop/danish +94 -0
  27. data/src/cue/lang/stop/dutch +107 -0
  28. data/src/cue/lang/stop/english +183 -0
  29. data/src/cue/lang/stop/esperanto +180 -0
  30. data/src/cue/lang/stop/farsi +966 -0
  31. data/src/cue/lang/stop/finnish +235 -0
  32. data/src/cue/lang/stop/french +543 -0
  33. data/src/cue/lang/stop/german +231 -0
  34. data/src/cue/lang/stop/greek +637 -0
  35. data/src/cue/lang/stop/hebrew +220 -0
  36. data/src/cue/lang/stop/hindi +97 -0
  37. data/src/cue/lang/stop/hungarian +202 -0
  38. data/src/cue/lang/stop/italian +279 -0
  39. data/src/cue/lang/stop/latin +1 -0
  40. data/src/cue/lang/stop/norwegian +176 -0
  41. data/src/cue/lang/stop/polish +138 -0
  42. data/src/cue/lang/stop/portuguese +204 -0
  43. data/src/cue/lang/stop/romanian +284 -0
  44. data/src/cue/lang/stop/russian +652 -0
  45. data/src/cue/lang/stop/slovak +110 -0
  46. data/src/cue/lang/stop/slovenian +448 -0
  47. data/src/cue/lang/stop/spanish +308 -0
  48. data/src/cue/lang/stop/swedish +114 -0
  49. data/src/cue/lang/stop/turkish +117 -0
  50. data/src/cue/lang/unicode/BlockUtil.java +103 -0
  51. data/src/cue/lang/unicode/Normalizer.java +55 -0
  52. data/src/cue/lang/unicode/Normalizer6.java +32 -0
  53. data/src/license.txt +201 -0
  54. data/src/wordcram/Anglers.java +137 -0
  55. data/src/wordcram/BBTree.java +133 -0
  56. data/src/wordcram/BBTreeBuilder.java +61 -0
  57. data/src/wordcram/Colorers.java +52 -0
  58. data/src/wordcram/EngineWord.java +73 -0
  59. data/src/wordcram/Fonters.java +17 -0
  60. data/src/wordcram/HsbWordColorer.java +28 -0
  61. data/src/wordcram/ImageShaper.java +91 -0
  62. data/src/wordcram/Observer.java +9 -0
  63. data/src/wordcram/PlacerHeatMap.java +134 -0
  64. data/src/wordcram/Placers.java +74 -0
  65. data/src/wordcram/PlottingWordNudger.java +38 -0
  66. data/src/wordcram/PlottingWordPlacer.java +36 -0
  67. data/src/wordcram/ProcessingWordRenderer.java +42 -0
  68. data/src/wordcram/RandomWordNudger.java +44 -0
  69. data/src/wordcram/RenderOptions.java +10 -0
  70. data/src/wordcram/ShapeBasedPlacer.java +66 -0
  71. data/src/wordcram/Sizers.java +54 -0
  72. data/src/wordcram/SketchCallbackObserver.java +70 -0
  73. data/src/wordcram/SpiralWordNudger.java +31 -0
  74. data/src/wordcram/SvgWordRenderer.java +110 -0
  75. data/src/wordcram/SwirlWordPlacer.java +25 -0
  76. data/src/wordcram/UpperLeftWordPlacer.java +27 -0
  77. data/src/wordcram/WaveWordPlacer.java +25 -0
  78. data/src/wordcram/Word.java +357 -0
  79. data/src/wordcram/WordAngler.java +20 -0
  80. data/src/wordcram/WordArray.java +18 -0
  81. data/src/wordcram/WordBag.java +31 -0
  82. data/src/wordcram/WordColorer.java +25 -0
  83. data/src/wordcram/WordCounter.java +96 -0
  84. data/src/wordcram/WordCram.java +920 -0
  85. data/src/wordcram/WordCramEngine.java +196 -0
  86. data/src/wordcram/WordFonter.java +24 -0
  87. data/src/wordcram/WordNudger.java +44 -0
  88. data/src/wordcram/WordPlacer.java +44 -0
  89. data/src/wordcram/WordRenderer.java +10 -0
  90. data/src/wordcram/WordShaper.java +78 -0
  91. data/src/wordcram/WordSizer.java +46 -0
  92. data/src/wordcram/WordSkipReason.java +42 -0
  93. data/src/wordcram/WordSorterAndScaler.java +31 -0
  94. data/src/wordcram/WordSource.java +5 -0
  95. data/src/wordcram/text/Html.java +15 -0
  96. data/src/wordcram/text/Html2Text.java +17 -0
  97. data/src/wordcram/text/Text.java +15 -0
  98. data/src/wordcram/text/TextFile.java +23 -0
  99. data/src/wordcram/text/TextSource.java +5 -0
  100. data/src/wordcram/text/WebPage.java +23 -0
  101. metadata +94 -5
  102. data/lib/cue.language.jar +0 -0
  103. data/lib/jsoup-1.7.2.jar +0 -0
  104. data/vendors/Rakefile +0 -51
@@ -0,0 +1,196 @@
1
+ package wordcram;
2
+
3
+ import java.awt.Color; // awt: turns P5-land color into awt color, for renderers
4
+ import java.awt.Shape; // awt: word->shape, skip if too small, pass it on
5
+ import java.awt.geom.Rectangle2D; // awt: to get bounding box width & height
6
+ import java.util.ArrayList;
7
+ import java.util.ListIterator;
8
+
9
+ import processing.core.PFont;
10
+ import processing.core.PVector;
11
+
12
+ class WordCramEngine {
13
+
14
+ private final WordRenderer renderer;
15
+
16
+ private final WordFonter fonter;
17
+ private final WordSizer sizer;
18
+ private final WordColorer colorer;
19
+ private final WordAngler angler;
20
+ private final WordPlacer placer;
21
+ private final WordNudger nudger;
22
+
23
+ private final ArrayList<EngineWord> eWords;
24
+ private final ListIterator<EngineWord> eWordIter;
25
+ private final ArrayList<EngineWord> drawnWords = new ArrayList<>();
26
+ private final ArrayList<Word> skippedWords = new ArrayList<>();
27
+
28
+ private final RenderOptions renderOptions;
29
+ private final Observer observer;
30
+
31
+ // TODO Damn, really need to break down that list of arguments.
32
+ WordCramEngine(WordRenderer renderer, Word[] words, WordFonter fonter, WordSizer sizer, WordColorer colorer, WordAngler angler, WordPlacer placer, WordNudger nudger, WordShaper shaper, BBTreeBuilder bbTreeBuilder, RenderOptions renderOptions, Observer observer) {
33
+ this.renderer = renderer;
34
+
35
+ this.fonter = fonter;
36
+ this.sizer = sizer;
37
+ this.colorer = colorer;
38
+ this.angler = angler;
39
+ this.placer = placer;
40
+ this.nudger = nudger;
41
+ this.observer = observer;
42
+
43
+ this.renderOptions = renderOptions;
44
+ this.eWords = wordsIntoEngineWords(words, shaper, bbTreeBuilder);
45
+ this.eWordIter = eWords.listIterator();
46
+ }
47
+
48
+ private ArrayList<EngineWord> wordsIntoEngineWords(Word[] words, WordShaper wordShaper, BBTreeBuilder bbTreeBuilder) {
49
+ ArrayList<EngineWord> engineWords = new ArrayList<>();
50
+
51
+ int maxNumberOfWords = words.length;
52
+ if (renderOptions.maxNumberOfWordsToDraw >= 0) {
53
+ maxNumberOfWords = Math.min(maxNumberOfWords, renderOptions.maxNumberOfWordsToDraw);
54
+ }
55
+
56
+ for (int i = 0; i < maxNumberOfWords; i++) {
57
+ Word word = words[i];
58
+ EngineWord eWord = new EngineWord(word, i, words.length, bbTreeBuilder);
59
+
60
+ PFont wordFont = word.getFont(fonter);
61
+ float wordSize = word.getSize(sizer, i, words.length);
62
+ float wordAngle = word.getAngle(angler);
63
+
64
+ Shape shape = wordShaper.getShapeFor(eWord.word.word, wordFont, wordSize, wordAngle);
65
+ if (isTooSmall(shape, renderOptions.minShapeSize)) {
66
+ skipWord(word, WordSkipReason.SHAPE_WAS_TOO_SMALL);
67
+ }
68
+ else {
69
+ eWord.setShape(shape, renderOptions.wordPadding);
70
+ engineWords.add(eWord); // DON'T add eWords with no shape.
71
+ }
72
+ }
73
+
74
+ for (int i = maxNumberOfWords; i < words.length; i++) {
75
+ skipWord(words[i], WordSkipReason.WAS_OVER_MAX_NUMBER_OF_WORDS);
76
+ }
77
+
78
+ return engineWords;
79
+ }
80
+
81
+ private boolean isTooSmall(Shape shape, int minShapeSize) {
82
+ if (minShapeSize < 1) {
83
+ minShapeSize = 1;
84
+ }
85
+ Rectangle2D r = shape.getBounds2D();
86
+
87
+ // Most words will be wider than tall, so this basically boils down to height.
88
+ // For the odd word like "I", we check width, too.
89
+ return r.getHeight() < minShapeSize || r.getWidth() < minShapeSize;
90
+ }
91
+
92
+ private void skipWord(Word word, WordSkipReason reason) {
93
+ // TODO delete these properties when starting a sketch, in case it's a re-run w/ the same words.
94
+ // NOTE: keep these as properties, because they (will be) deleted when the WordCramEngine re-runs.
95
+ word.wasSkippedBecause(reason);
96
+ skippedWords.add(word);
97
+ observer.wordSkipped(word);
98
+ }
99
+
100
+ boolean hasMore() {
101
+ return eWordIter.hasNext();
102
+ }
103
+
104
+ void drawAll() {
105
+ observer.beginDraw();
106
+ while(hasMore()) {
107
+ drawNext();
108
+ }
109
+ renderer.finish();
110
+ observer.endDraw();
111
+ }
112
+
113
+ void drawNext() {
114
+ if (!hasMore()) return;
115
+ EngineWord eWord = eWordIter.next();
116
+ boolean wasPlaced = placeWord(eWord);
117
+ if (wasPlaced) { // TODO unit test (somehow)
118
+ drawWordImage(eWord);
119
+ observer.wordDrawn(eWord.word);
120
+ }
121
+ }
122
+
123
+ private boolean placeWord(EngineWord eWord) {
124
+ Word word = eWord.word;
125
+ Rectangle2D rect = eWord.getShape().getBounds2D(); // TODO can we move these into EngineWord.setDesiredLocation? Does that make sense?
126
+ int wordImageWidth = (int)rect.getWidth();
127
+ int wordImageHeight = (int)rect.getHeight();
128
+
129
+ eWord.setDesiredLocation(placer, eWords.size(), wordImageWidth, wordImageHeight, renderer.getWidth(), renderer.getHeight());
130
+
131
+ // Set maximum number of placement trials
132
+ int maxAttemptsToPlace = renderOptions.maxAttemptsToPlaceWord > 0 ?
133
+ renderOptions.maxAttemptsToPlaceWord :
134
+ calculateMaxAttemptsFromWordWeight(word);
135
+
136
+ EngineWord lastCollidedWith = null;
137
+ for (int attempt = 0; attempt < maxAttemptsToPlace; attempt++) {
138
+
139
+ eWord.nudge(nudger.nudgeFor(word, attempt));
140
+
141
+ PVector loc = eWord.getCurrentLocation();
142
+ if (loc.x < 0 || loc.y < 0 || loc.x + wordImageWidth >= renderer.getWidth() || loc.y + wordImageHeight >= renderer.getHeight()) {
143
+ continue;
144
+ }
145
+
146
+ if (lastCollidedWith != null && eWord.overlaps(lastCollidedWith)) {
147
+ continue;
148
+ }
149
+
150
+ boolean foundOverlap = false;
151
+ for (EngineWord otherWord : drawnWords) {
152
+ if (eWord.overlaps(otherWord)) {
153
+ foundOverlap = true;
154
+ lastCollidedWith = otherWord;
155
+ break;
156
+ }
157
+ }
158
+
159
+ if (!foundOverlap) {
160
+ eWord.finalizeLocation();
161
+ return true;
162
+ }
163
+ }
164
+
165
+ skipWord(eWord.word, WordSkipReason.NO_SPACE);
166
+ return false;
167
+ }
168
+
169
+ private int calculateMaxAttemptsFromWordWeight(Word word) {
170
+ return (int)((1.0 - word.weight) * 600) + 100;
171
+ }
172
+
173
+ private void drawWordImage(EngineWord word) {
174
+ drawnWords.add(word);
175
+ renderer.drawWord(word, new Color(word.word.getColor(colorer), true));
176
+ }
177
+
178
+ Word getWordAt(float x, float y) {
179
+ int size = drawnWords.size() - 1;
180
+ for (int i = size; i >= 0; i--) {
181
+ EngineWord eWord = drawnWords.get(i);
182
+ if (eWord.containsPoint(x, y)) {
183
+ return eWord.word;
184
+ }
185
+ }
186
+ return null;
187
+ }
188
+
189
+ Word[] getSkippedWords() {
190
+ return skippedWords.toArray(new Word[0]);
191
+ }
192
+
193
+ float getProgress() {
194
+ return (float) eWordIter.nextIndex() / eWords.size();
195
+ }
196
+ }
@@ -0,0 +1,24 @@
1
+ package wordcram;
2
+
3
+ import processing.core.PFont;
4
+
5
+ /**
6
+ * A WordFonter tells WordCram what font to render a word in.
7
+ * <p>
8
+ * Some useful implementations are available in {@link Fonters}.
9
+ * <p>
10
+ * <i>The name "WordFonter" was picked because it matches the others: WordColorer,
11
+ * WordPlacer, WordSizer, etc. Apologies if it sounds a bit weird to your ear; I
12
+ * eventually got used to it.</i>
13
+ *
14
+ * @author Dan Bernier
15
+ */
16
+ public interface WordFonter {
17
+
18
+ /**
19
+ * What font should this {@link Word} be drawn in?
20
+ * @param word the word to pick the PFont for
21
+ * @return the PFont for the word
22
+ */
23
+ public PFont fontFor(Word word);
24
+ }
@@ -0,0 +1,44 @@
1
+ package wordcram;
2
+
3
+ import processing.core.PVector;
4
+
5
+ /**
6
+ * Once a WordPlacer tells WordCram where a word <i>should</i> go, a WordNudger
7
+ * tells WordCram how to nudge it around the field, until it fits in with the
8
+ * other words around it, or the WordCram gives up on the word.
9
+ * <p>
10
+ * WordCram gets a PVector from the nudger, and adds it to the word's desired
11
+ * location, to find the next spot to try fitting the word. Note that the
12
+ * PVectors returned from a nudger <i><b>don't accumulate</b></i>: if the placer
13
+ * puts a Word at (0, 0), and the nudger returns (1, 1), and then (2, 2),
14
+ * WordCram will try the word at (1, 1), and then (2, 2) -- <i>not</i> (1, 1)
15
+ * and then (3, 3).
16
+ * <p>
17
+ * A WordNudger should probably start nudging the word only a little, to keep it
18
+ * near its desired location, and gradually nudge it more and more, so that,
19
+ * even if the desired area is congested, the word can still fit in somewhere.
20
+ * This is why the WordCram passes in <code>attemptNumber</code>: it's the
21
+ * number of times it's attempted to place the word. This could (for example)
22
+ * scale the PVector, since the nudges don't accumulate (see above).
23
+ *
24
+ * @see RandomWordNudger
25
+ * @see SpiralWordNudger
26
+ *
27
+ * @author Dan Bernier
28
+ */
29
+ public interface WordNudger {
30
+
31
+ /**
32
+ * How should this word be nudged, this time?
33
+ *
34
+ * @param word
35
+ * the word to nudge
36
+ * @param attemptNumber
37
+ * how many times WordCram has tried to place this word; starts
38
+ * at zero, and ends at
39
+ * <code>(int)((1.0-word.weight) * 600) + 100</code>
40
+ * @return the PVector to add to the word's desired location, to get the
41
+ * next spot to try fitting the word
42
+ */
43
+ public PVector nudgeFor(Word word, int attemptNumber);
44
+ }
@@ -0,0 +1,44 @@
1
+ package wordcram;
2
+
3
+ import processing.core.PVector;
4
+
5
+ /**
6
+ * A WordPlacer tells WordCram where to place a word (in x,y coordinates) on the field.
7
+ * <p>
8
+ * A WordPlacer only suggests: the WordCram will try to place the Word where the
9
+ * WordPlacer tells it to, but if the Word overlaps other Words, a WordNudger
10
+ * will suggest different near-by spots for the Word until it fits, or until the
11
+ * WordCram gives up.
12
+ * <p>
13
+ * Some useful implementations are available in {@link Placers}.
14
+ *
15
+ * @author Dan Bernier
16
+ */
17
+ public interface WordPlacer {
18
+
19
+ /**
20
+ * Where should this {@link Word} be drawn on the field?
21
+ *
22
+ * @param word
23
+ * The Word to place. A typical WordPlacer might use the Word's
24
+ * weight.
25
+ * @param wordIndex
26
+ * The index (rank) of the Word to place. Since this isn't a
27
+ * property of the Word, it's passed in as well.
28
+ * @param wordsCount
29
+ * The total number of words. Gives a context to wordIndex:
30
+ * "Word {wordIndex} of {wordsCount}".
31
+ * @param wordImageWidth
32
+ * The width of the word image.
33
+ * @param wordImageHeight
34
+ * The height of the word image.
35
+ * @param fieldWidth
36
+ * The width of the field.
37
+ * @param fieldHeight
38
+ * The height of the field.
39
+ * @return the desired location for a Word on the field, as a 2D PVector.
40
+ */
41
+ public abstract PVector place(Word word, int wordIndex, int wordsCount,
42
+ int wordImageWidth, int wordImageHeight, int fieldWidth,
43
+ int fieldHeight);
44
+ }
@@ -0,0 +1,10 @@
1
+ package wordcram;
2
+
3
+ import java.awt.Color; // awt: JUST for the interface (this IS an interface)
4
+
5
+ interface WordRenderer {
6
+ int getWidth();
7
+ int getHeight();
8
+ void drawWord(EngineWord word, Color color);
9
+ void finish();
10
+ }
@@ -0,0 +1,78 @@
1
+ package wordcram;
2
+
3
+ import java.awt.Font; // awt: font+word=shape
4
+ import java.awt.Shape; // awt: font+word=shape
5
+ import java.awt.font.FontRenderContext; // awt: font+word=shape
6
+ import java.awt.font.GlyphVector; // awt: font+word=shape
7
+ import java.awt.geom.AffineTransform; // awt: move and rotate shape
8
+ import java.awt.geom.Rectangle2D; // awt: move shape
9
+
10
+ import processing.core.PFont;
11
+
12
+ public class WordShaper {
13
+ private final FontRenderContext frc = new FontRenderContext(null, true, true);
14
+
15
+
16
+ private boolean rightToLeft;
17
+ public WordShaper(boolean rightToLeft) {
18
+ this.rightToLeft = rightToLeft;
19
+ }
20
+ public WordShaper() {
21
+ this(false);
22
+ }
23
+
24
+
25
+ public Shape getShapeFor(String word, Font font, float fontSize, float angle) {
26
+ Shape shape = makeShape(word, sizeFont(font, fontSize));
27
+ return moveToOrigin(rotate(shape, angle));
28
+ }
29
+
30
+ public Shape getShapeFor(String word, Font font) {
31
+ return getShapeFor(word, font, font.getSize2D(), 0);
32
+ }
33
+
34
+ public Shape getShapeFor(String word, PFont pFont, float fontSize, float angle) {
35
+ return getShapeFor(word, (Font)pFont.getNative(), fontSize, angle);
36
+ }
37
+
38
+ public Shape getShapeFor(String word, PFont pFont) {
39
+ return getShapeFor(word, (Font)pFont.getNative());
40
+ }
41
+
42
+
43
+
44
+ private Font sizeFont(Font unsizedFont, float fontSize) {
45
+ if (fontSize == unsizedFont.getSize2D()) {
46
+ return unsizedFont;
47
+ }
48
+ return unsizedFont.deriveFont(fontSize);
49
+ }
50
+
51
+ private Shape makeShape(String word, Font font) {
52
+ char[] chars = word.toCharArray();
53
+
54
+ // TODO hmm: this doesn't render newlines. Hrm. If your word text is "foo\nbar", you get "foobar".
55
+ GlyphVector gv = font.layoutGlyphVector(frc, chars, 0, chars.length,
56
+ this.rightToLeft ? Font.LAYOUT_RIGHT_TO_LEFT : Font.LAYOUT_LEFT_TO_RIGHT);
57
+
58
+ return gv.getOutline();
59
+ }
60
+
61
+ private Shape rotate(Shape shape, float rotation) {
62
+ if (rotation == 0) {
63
+ return shape;
64
+ }
65
+
66
+ return AffineTransform.getRotateInstance(rotation).createTransformedShape(shape);
67
+ }
68
+
69
+ private Shape moveToOrigin(Shape shape) {
70
+ Rectangle2D rect = shape.getBounds2D();
71
+
72
+ if (rect.getX() == 0 && rect.getY() == 0) {
73
+ return shape;
74
+ }
75
+
76
+ return AffineTransform.getTranslateInstance(-rect.getX(), -rect.getY()).createTransformedShape(shape);
77
+ }
78
+ }
@@ -0,0 +1,46 @@
1
+ package wordcram;
2
+
3
+ /**
4
+ * A WordSizer tells WordCram how big to render each word.
5
+ * You'll pass a WordSizer to WordCram via {@link WordCram#withSizer(WordSizer)}.
6
+ * <p>
7
+ * Some useful implementations are available in {@link Sizers}.
8
+ *
9
+ * @author Dan Bernier
10
+ */
11
+ public interface WordSizer {
12
+
13
+ /**
14
+ * How big should this {@link Word} be rendered?
15
+ * <p>
16
+ * Generally, a word cloud draws more important words bigger. Two typical
17
+ * ways to measure word's importance are its weight, and its rank (its
18
+ * position in the list of words, sorted by weight).
19
+ * <p>
20
+ * Given that, sizeFor is passed the Word (which knows its own weight), its
21
+ * rank, and the total number of words.
22
+ * <p>
23
+ * For example, given the text "I think I can I think", the words would look
24
+ * like this:
25
+ * <ul>
26
+ * <li>"I", weight 1.0 (3/3), rank 1</li>
27
+ * <li>"think", weight 0.667 (2/3), rank 2</li>
28
+ * <li>"can", weight 0.333 (1/3), rank 3</li>
29
+ * </ul>
30
+ * ...and the WordSizer would be called with the following values:
31
+ * <ul>
32
+ * <li>Word "I" (weight 1.0), 1, 3</li>
33
+ * <li>Word "think" (weight 0.667), 2, 3</li>
34
+ * <li>Word "can" (weight 0.333), 3, 3</li>
35
+ * </ul>
36
+ *
37
+ * @param word
38
+ * the Word to determine the size of
39
+ * @param wordRank
40
+ * the rank of the Word
41
+ * @param wordCount
42
+ * the total number of Words being rendered
43
+ * @return the size to render the Word
44
+ */
45
+ public float sizeFor(Word word, int wordRank, int wordCount);
46
+ }