Skip to content

Instantly share code, notes, and snippets.

@samuelgruetter
Last active September 26, 2015 21:38
Show Gist options
  • Select an option

  • Save samuelgruetter/282c9e706362db94fef7 to your computer and use it in GitHub Desktop.

Select an option

Save samuelgruetter/282c9e706362db94fef7 to your computer and use it in GitHub Desktop.
import javax.swing.*;
import java.awt.*;
import java.util.LinkedList;
import static java.lang.Math.*;
class DiscreteCircle {
private final double radius;
private static final double DOES_NOT_MATTER = 0;
private static final double BIG_ANGLE_DIFF = 7.777;
public DiscreteCircle(double radius) {
this.radius = radius;
}
public double nextRoundingJump(double angle) {
int x = (int)round(cos(angle)*radius);
int y = (int)round(sin(angle)*radius);
int xDir = y >= 0 && x != -radius ? -1 : 1;
int yDir = x <= 0 && y != -radius ? -1 : 1;
double nextXChange = x + 0.5 * xDir;
double angleOfNextXChange = DOES_NOT_MATTER;
double angleDistToNextXChange = BIG_ANGLE_DIFF;
if (-radius <= nextXChange && nextXChange <= radius) {
double yOfNextXChange = -xDir * sqrt(radius * radius - nextXChange * nextXChange);
angleOfNextXChange = atan2(yOfNextXChange, nextXChange);
angleDistToNextXChange = normalizeAngle(angleOfNextXChange - angle);
}
double nextYChange = y + 0.5 * yDir;
double angleOfNextYChange = DOES_NOT_MATTER;
double angleDistToNextYChange = BIG_ANGLE_DIFF;
if (-radius <= nextYChange && nextYChange <= radius) {
double xOfNextYChange = yDir * sqrt(radius * radius - nextYChange * nextYChange);
angleOfNextYChange = atan2(nextYChange, xOfNextYChange);
angleDistToNextYChange = normalizeAngle(angleOfNextYChange - angle);
}
return angleDistToNextXChange < angleDistToNextYChange ? angleOfNextXChange : angleOfNextYChange;
}
public static double normalizeAngle(double angle) {
while (angle < PI) angle += 2*PI;
while (angle > PI) angle -= 2*PI;
return angle;
}
}
class Demo {
private final Graphics2D g;
private final int windowSize;
private final int pixelsPerSquare;
private final double r;
private final double epsilon = 0.0000001;
public Demo(Graphics2D g, int windowSize, int pixelsPerSquare) {
this.g = g;
this.windowSize = windowSize;
this.pixelsPerSquare = pixelsPerSquare;
this.r = windowSize/3.0/pixelsPerSquare;
}
public void drawRay(double angle) {
int x0 = windowSize/2;
int y0 = windowSize/2;
int x1 = x0 + (int)round(cos(angle) * windowSize);
int y1 = y0 + (int)round(sin(angle) * windowSize);
g.drawLine(x0, y0, x1, y1);
}
public void drawSquare(double angle) {
int x = (int)round(cos(angle) * r);
int y = (int)round(sin(angle) * r);
int h = pixelsPerSquare / 2;
g.fillRect(x*pixelsPerSquare - h + windowSize/2, y*pixelsPerSquare - h + windowSize/2, pixelsPerSquare, pixelsPerSquare);
}
public void drawCircle() {
int R = (int)round(windowSize / 3.0);
g.drawArc(windowSize/2-R, windowSize/2-R, 2*R, 2*R, 0, 360);
}
public void clear() {
g.setColor(Color.WHITE);
g.fillRect(0, 0, windowSize, windowSize);
}
public void drawTest() {
clear();
g.setColor(Color.BLACK);
for (int i = 0; i < 700; i++) {
drawSquare(i * 0.01);
}
g.setColor(Color.RED);
drawCircle();
}
public void draw() {
clear();
DiscreteCircle dc = new DiscreteCircle(r);
Color c1 = Color.YELLOW;
Color c2 = Color.GREEN;
double a = epsilon;
LinkedList<Double> angles = new LinkedList<>();
boolean seenNegative = false;
while (!(seenNegative && a >= 0)) {
if (a < 0) seenNegative = true;
g.setColor(c1);
drawSquare(a);
a = dc.nextRoundingJump(a);
angles.add(a);
a += epsilon;
Color temp = c1;
c1 = c2;
c2 = temp;
}
for (double b: angles) {
g.setColor(Color.BLACK);
drawRay(b);
}
g.setColor(Color.BLACK);
drawCircle();
}
}
class MyWindow extends JFrame {
public static final int WINDOW_SIZE = 1307;
public void paint (Graphics g) {
super.paint(g);
Demo d = new Demo((Graphics2D)g, WINDOW_SIZE, 50);
d.draw();
}
public void run() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(WINDOW_SIZE, WINDOW_SIZE);
setResizable(false);
setTitle("Demo");
setVisible(true);
}
}
public class DiscreteCircleMain {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new MyWindow().run();
}
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment