1
0
mirror of https://github.com/kennycason/kumo synced 2025-03-26 08:48:49 -04:00

fixed the calculation of the maximum spiral radius and added a test to it

the maximum spiral radius might be bigger or smaller than the image width, e.g. if the image height is bigger than the width.
This commit is contained in:
joerg1985 2019-01-31 22:04:38 +01:00
parent 1ca095b4e7
commit ee9ad38574
2 changed files with 132 additions and 2 deletions
kumo-core/src
main/java/com/kennycason/kumo
test/java/com/kennycason/kumo

View File

@ -161,6 +161,21 @@ public class WordCloud {
graphics2.drawImage(backgroundBufferedImage, 0, 0, null);
}
/**
* compute the maximum radius for the placing spiral
*
* @param dimension the size of the backgound
* @param start the center of the spiral
* @return the maximum usefull radius
*/
static int computeRadius(Dimension dimension, Point start) {
int maxDistanceX = Math.max(start.x, dimension.width - start.x) + 1;
int maxDistanceY = Math.max(start.y, dimension.height - start.y) + 1;
// we use the pythagorean theorem to determinate the maximum radius
return (int) Math.ceil(Math.sqrt(maxDistanceX * maxDistanceX + maxDistanceY * maxDistanceY));
}
/**
* try to place in center, build out in a spiral trying to place words for N steps
* @param word the word being placed
@ -169,12 +184,12 @@ public class WordCloud {
protected boolean place(final Word word, final Point start) {
final Graphics graphics = this.bufferedImage.getGraphics();
final int maxRadius = dimension.width;
final int maxRadius = computeRadius(dimension, start);
for (int r = 0; r < maxRadius; r += 2) {
for (int x = -r; x <= r; x++) {
if (start.x + x < 0) { continue; }
if (start.x + x >= maxRadius) { continue; }
if (start.x + x >= dimension.width) { continue; }
boolean placed = false;
word.getPosition().x = start.x + x;

View File

@ -0,0 +1,115 @@
package com.kennycason.kumo;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.imageio.ImageIO;
import org.junit.Assert;
import org.junit.Test;
/**
*
* @author joerg1985
*/
public class SpiralTest {
@Test
public void NewImplementationVsOldImplementation() throws IOException {
// draw the spiral as image?
// red pixels -> only returned by the old implementation
// blue pixels -> only returned by the new implementation
// pink pixels -> returned by the old and the new implementation
boolean debug = false;
final int white = 0;
final int red = 0xFFFF0000;
final int blue = 0xFF0000FF;
final int pink = red | blue;
// we seed to get the same numbers on each run
Random random = new Random(42);
for (int i = 0; i < 20; i++) {
Dimension dimension = new Dimension(
100 + random.nextInt(900),
100 + random.nextInt(900)
);
for (int j = 0; j < 20; j++) {
Point start = new Point(
random.nextInt(dimension.width),
random.nextInt(dimension.height)
);
// the old implementation did not repect images higher than wide
int originalRadius = dimension.width;
int optimizedRadius = WordCloud.computeRadius(dimension, start);
List<Point> original = spiral(dimension, start, originalRadius);
List<Point> optimized = spiral(dimension, start, optimizedRadius);
BufferedImage img = new BufferedImage(
dimension.width, dimension.height, BufferedImage.TYPE_4BYTE_ABGR
);
original.forEach((p) -> img.setRGB(p.x, p.y, red));
optimized.forEach((p) -> {
if (img.getRGB(p.x, p.y) != 0) {
img.setRGB(p.x, p.y, pink);
} else {
img.setRGB(p.x, p.y, blue);
}
});
boolean next = false;
for (int y = 0; !next && y < dimension.height; y++) {
for (int x = 0; !next && x < dimension.width; x++) {
int rgb = img.getRGB(x, y);
if (rgb == red) {
ImageIO.write(img, "png", new File("output\\failed_spiral_test.png"));
Assert.fail();
} else if (debug && rgb != white && rgb != pink) {
ImageIO.write(img, "png", new File("output\\debug_spiral_test_" + System.currentTimeMillis() + ".png"));
next = true;
}
}
}
}
}
}
private List<Point> spiral(Dimension dimension, Point start, final int maxRadius) {
List<Point> points = new ArrayList<>();
for (int r = 0; r < maxRadius; r += 2) {
for (int x = -r; x <= r; x++) {
if (start.x + x < 0) {
continue;
}
if (start.x + x >= dimension.width) {
continue;
}
// try positive root
final int y1 = (int) Math.sqrt(r * r - x * x);
if (start.y + y1 >= 0 && start.y + y1 < dimension.height) {
points.add(new Point(start.x + x, start.y + y1));
}
// try negative root
final int y2 = -y1;
if (start.y + y2 >= 0 && start.y + y2 < dimension.height) {
points.add(new Point(start.x + x, start.y + y2));
}
}
}
return points;
}
}