Last active
September 26, 2015 21:38
-
-
Save samuelgruetter/282c9e706362db94fef7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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