Mandelbrot set: Difference between revisions
Content added Content deleted
Line 4,263: | Line 4,263: | ||
public class Mandelbrot extends JFrame { |
public class Mandelbrot extends JFrame { |
||
private static final long serialVersionUID = 1L; |
|||
private Insets insets; |
|||
private int width, height; |
|||
private double widthHeightRatio; |
|||
private int minX, minY; |
|||
private double Zoom; |
|||
private int mpX, mpY, mdX, mdY; |
|||
private boolean isCtrlDown, ctrl; |
|||
private Stack stack = new Stack(); |
|||
private BufferedImage image; |
|||
boolean paint = true; |
|||
public static void main(String[] args) { |
|||
public static void main(String[] args) { |
|||
new Mandelbrot(800, 600); // (800, 600), (1024, 768), (1600, 900) |
|||
new Mandelbrot(800, 600); // (800, 600), (1024, 768), (1600, 900) |
|||
} |
|||
} |
|||
public Mandelbrot(int width, int height) { |
|||
public Mandelbrot(int width, int height) { |
|||
super("Mandelbrot Set"); |
|||
setResizable(false); |
|||
setResizable(false); |
|||
setDefaultCloseOperation(EXIT_ON_CLOSE); |
|||
setDefaultCloseOperation(EXIT_ON_CLOSE); |
|||
Dimension screen = getToolkit().getScreenSize(); |
|||
Dimension screen = getToolkit().getScreenSize(); |
|||
setBounds( |
|||
setBounds( |
|||
((int) screen.getWidth() - width) / 2, |
|||
((int) screen.getWidth() - width) / 2, |
|||
((int) screen.getHeight() - height) / 2, |
|||
width, |
|||
width, |
|||
height |
|||
height |
|||
); |
|||
); |
|||
addMouseListener(mouseAdapter); |
|||
addMouseListener(mouseAdapter); |
|||
addMouseMotionListener(mouseAdapter); |
|||
addKeyListener( |
|||
addKeyListener( |
|||
new KeyAdapter() { |
|||
new KeyAdapter() { |
|||
public void keyPressed(KeyEvent e) { |
|||
public void keyPressed(KeyEvent e) { |
|||
isCtrlDown = e.isControlDown(); |
|||
isCtrlDown = e.isControlDown(); |
|||
} |
|||
} |
|||
public void keyReleased(KeyEvent e) { |
|||
public void keyReleased(KeyEvent e) { |
|||
isCtrlDown = e.isControlDown(); |
|||
isCtrlDown = e.isControlDown(); |
|||
} |
|||
} |
|||
public void keyTyped(KeyEvent e) { |
|||
public void keyTyped(KeyEvent e) { |
|||
char c = e.getKeyChar(); |
|||
char c = e.getKeyChar(); |
|||
boolean isEsc = c == KeyEvent.VK_ESCAPE; |
|||
boolean isEsc = c == KeyEvent.VK_ESCAPE; |
|||
if (!isEsc && c != KeyEvent.VK_BACK_SLASH) return; |
|||
stack.pop(isEsc); |
|||
stack.pop(isEsc); |
|||
repaint(); |
|||
paint = true; |
|||
} |
|||
printPoint(); |
|||
} |
|||
repaint(); |
|||
); |
|||
} |
|||
setVisible(true); |
|||
} |
|||
insets = getInsets(); |
|||
); |
|||
this.width = width -= insets.left + insets.right; |
|||
setVisible(true); |
|||
this.height = height -= insets.top + insets.bottom; |
|||
insets = getInsets(); |
|||
widthHeightRatio = (double) width / height; |
|||
this.width = width -= insets.left + insets.right; |
|||
this.height = height -= insets.top + insets.bottom; |
|||
minY = -height / 2; |
|||
widthHeightRatio = (double) width / height; |
|||
Zoom = .005; |
|||
minX = -width / 2 - 125; |
|||
System.out.println(Zoom); |
|||
minY = -height / 2; |
|||
} |
|||
Zoom = .005; |
|||
paint = true; |
|||
private MouseAdapter mouseAdapter = new MouseAdapter() { |
|||
printPoint(); |
|||
public void mouseClicked(MouseEvent e) { |
|||
} |
|||
stack.push(false); |
|||
if (!ctrl) { |
|||
private MouseAdapter mouseAdapter = new MouseAdapter() { |
|||
minX -= (double) width / 2 ; |
|||
public void mouseClicked(MouseEvent e) { |
|||
minY -= (double) height / 2; |
|||
stack.push(false); |
|||
} |
|||
if (!ctrl) { |
|||
minX += e.getX() - insets.left; |
|||
minX -= (double) width / 2 ; |
|||
minY += e.getY() - insets.top; |
|||
minY -= (double) height / 2; |
|||
ctrl = false; |
|||
} |
|||
repaint(); |
|||
minX += e.getX() - insets.left; |
|||
} |
|||
minY += e.getY() - insets.top; |
|||
public void mousePressed(MouseEvent e) { |
|||
ctrl = false; |
|||
mpX = e.getX(); |
|||
paint = true; |
|||
mpY = e.getY(); |
|||
printPoint(); |
|||
ctrl = isCtrlDown; |
|||
repaint(); |
|||
} |
|||
} |
|||
public void mouseDragged(MouseEvent e) { |
|||
public void mousePressed(MouseEvent e) { |
|||
if (!ctrl) return; |
|||
mpX = e.getX(); |
|||
setMdCoord(e); |
|||
mpY = e.getY(); |
|||
repaint(); |
|||
ctrl = isCtrlDown; |
|||
} |
|||
} |
|||
private void setMdCoord(MouseEvent e) { |
|||
public void mouseDragged(MouseEvent e) { |
|||
int dx = e.getX() - mpX; |
|||
if (!ctrl) return; |
|||
int dy = e.getY() - mpY; |
|||
setMdCoord(e); |
|||
mdX = (int) (mpX + max(abs(dx), abs(dy)*widthHeightRatio) * signum(dx)); |
|||
repaint(); |
|||
mdY = (int) (mpY + max(abs(dy), abs(dx)/widthHeightRatio) * signum(dy)); |
|||
} |
|||
acceptIf(insets.left, ge(mdX), setMdXY); |
|||
private void setMdCoord(MouseEvent e) { |
|||
acceptIf(insets.top, ge(mdY), setMdYX); |
|||
int dx = e.getX() - mpX; |
|||
acceptIf(insets.left+width-1, le(mdX), setMdXY); |
|||
int dy = e.getY() - mpY; |
|||
acceptIf(insets.top+height-1, le(mdY), setMdYX); |
|||
mdX = (int) (mpX + max(abs(dx), abs(dy)*widthHeightRatio) * signum(dx)); |
|||
} |
|||
mdY = (int) (mpY + max(abs(dy), abs(dx)/widthHeightRatio) * signum(dy)); |
|||
private void acceptIf(int value, Predicate<Integer> p, Consumer<Integer> c) { if (p.test(value)) c.accept(value); } |
|||
acceptIf(insets.left, ge(mdX), setMdXY); |
|||
private Predicate<Integer> ge(int md) { return v-> v >= md; } |
|||
acceptIf(insets.top, ge(mdY), setMdYX); |
|||
private Predicate<Integer> le(int md) { return v-> v <= md; } |
|||
acceptIf(insets.left+width-1, le(mdX), setMdXY); |
|||
private Consumer<Integer> setMdXY = v-> mdY = (int) (mpY + abs((mdX=v)-mpX)/widthHeightRatio * signum(mdY-mpY)); |
|||
acceptIf(insets.top+height-1, le(mdY), setMdYX); |
|||
private Consumer<Integer> setMdYX = v-> mdX = (int) (mpX + abs((mdY=v)-mpY)*widthHeightRatio * signum(mdX-mpX)); |
|||
} |
|||
public void mouseReleased(MouseEvent e) { |
|||
private void acceptIf(int value, Predicate<Integer> p, Consumer<Integer> c) { if (p.test(value)) c.accept(value); } |
|||
if (e.getX() == mpX && e.getY() == mpY) return; |
|||
private Predicate<Integer> ge(int md) { return v-> v >= md; } |
|||
stack.push(ctrl); |
|||
private Predicate<Integer> le(int md) { return v-> v <= md; } |
|||
if (!ctrl) { |
|||
private Consumer<Integer> setMdXY = v-> mdY = (int) (mpY + abs((mdX=v)-mpX)/widthHeightRatio * signum(mdY-mpY)); |
|||
minX += mpX - (mdX = e.getX()); |
|||
private Consumer<Integer> setMdYX = v-> mdX = (int) (mpX + abs((mdY=v)-mpY)*widthHeightRatio * signum(mdX-mpX)); |
|||
minY += mpY - (mdY = e.getY()); |
|||
public void mouseReleased(MouseEvent e) { |
|||
} |
|||
if (e.getX() == mpX && e.getY() == mpY) return; |
|||
else { |
|||
stack.push(ctrl); |
|||
setMdCoord(e); |
|||
if (!ctrl) { |
|||
if (mdX < mpX) {int t=mpX; mpX=mdX; mdX=t; } |
|||
minX += mpX - (mdX = e.getX()); |
|||
if (mdY < mpY) {int t=mpY; mpY=mdY; mdY=t; } |
|||
minY += mpY - (mdY = e.getY()); |
|||
minX += mpX - insets.left; |
|||
} |
|||
minY += mpY - insets.top; |
|||
else { |
|||
double rZoom = (double) width / abs(mdX - mpX); |
|||
setMdCoord(e); |
|||
minX *= rZoom; |
|||
if (mdX < mpX) {int t=mpX; mpX=mdX; mdX=t; } |
|||
minY *= rZoom; |
|||
if (mdY < mpY) {int t=mpY; mpY=mdY; mdY=t; } |
|||
Zoom /= rZoom; |
|||
minX += mpX - insets.left; |
|||
System.out.println(Zoom); |
|||
minY += mpY - insets.top; |
|||
} |
|||
double rZoom = (double) width / abs(mdX - mpX); |
|||
ctrl = false; |
|||
minX *= rZoom; |
|||
repaint(); |
|||
minY *= rZoom; |
|||
} |
|||
Zoom /= rZoom; |
|||
}; |
|||
} |
|||
ctrl = false; |
|||
private class Stack extends java.util.Stack<Object[]> { |
|||
paint = true; |
|||
private static final long serialVersionUID = 1L; |
|||
printPoint(); |
|||
public void push(boolean type) { |
|||
repaint(); |
|||
push(new Object[] {type, minX, minY, Zoom}); |
|||
} |
|||
} |
|||
}; |
|||
public synchronized void pop(boolean type) { |
|||
for (;;) { |
|||
private void printPoint() { |
|||
if (empty()) return; |
|||
System.out.printf("%g %g%+gi .. %g%+gi ", Zoom, Zoom*minX, Zoom*minY, Zoom*(minX+width), Zoom*(minY+height)); |
|||
Object[] d = super.pop(); |
|||
} |
|||
minX = (Integer) d[1]; |
|||
minY = (Integer) d[2]; |
|||
private class Stack extends java.util.Stack<Object[]> { |
|||
Zoom = (Double) d[3]; |
|||
private static final long serialVersionUID = 1L; |
|||
if (!type || (Boolean) d[0]) return; |
|||
public void push(boolean type) { |
|||
} |
|||
push(new Object[] {type, minX, minY, Zoom}); |
|||
} |
|||
} |
|||
} |
|||
public synchronized void pop(boolean type) { |
|||
for (;;) { |
|||
@Override |
|||
if (empty()) return; |
|||
public void paint(Graphics g) { |
|||
Object[] d = super.pop(); |
|||
if (!ctrl) image = newImage(); |
|||
minX = (Integer) d[1]; |
|||
g.drawImage(image, insets.left, insets.top, this); |
|||
minY = (Integer) d[2]; |
|||
//g.setColor(Color.lightGray); |
|||
Zoom = (Double) d[3]; |
|||
//g.fillRect(7, height + insets.top - 22, 426, 15); |
|||
if (!type || (Boolean) d[0]) return; |
|||
//g.setColor(Color.black); |
|||
} |
|||
//g.drawString(String.format("%e %e %e %e %e",minX*Zoom,minY*Zoom,maxX*Zoom,maxY*Zoom,Zoom),10,height+insets.top-10); |
|||
} |
|||
//g.drawLine(insets.left+width/2, insets.top+0, insets.left+width/2, insets.top+height); |
|||
} |
|||
//g.drawLine(insets.left+0, insets.top+height/2, insets.left+width, insets.top+height/2); |
|||
if (!ctrl) return; |
|||
@Override |
|||
g.drawRect(min(mpX, mdX), min(mpY, mdY), abs(mpX - mdX), abs(mpY - mdY)); |
|||
public void paint(Graphics g) { |
|||
} |
|||
if (paint) try { |
|||
newImage(); |
|||
} |
|||
finally { |
|||
paint = false; |
|||
System.out.println("done!"); |
|||
} |
|||
g.drawImage(image, insets.left, insets.top, this); |
|||
//g.drawLine(insets.left+width/2, insets.top+0, insets.left+width/2, insets.top+height); |
|||
//g.drawLine(insets.left+0, insets.top+height/2, insets.left+width, insets.top+height/2); |
|||
if (!ctrl) return; |
|||
g.drawRect(min(mpX, mdX), min(mpY, mdY), abs(mpX - mdX), abs(mpY - mdY)); |
|||
} |
|||
private BufferedImage newImage() { |
|||
int maxX = minX + width; |
|||
int maxY = minY + height; |
|||
image = new BufferedImage(width, height, TYPE_INT_RGB); |
|||
for (int x = minX; x < maxX; x+=1) { |
|||
double r = x * Zoom; |
|||
for (int y = minY; y < maxY; y+=1) { |
|||
double i = y * Zoom; |
|||
//System.out.printf("%+f%+fi\n", r, i); |
|||
// 0f 1/6f 1/3f 1/2f 2/3f 5/6f |
|||
//straight -> red yellow green cian blue magenta <- reverse |
|||
image.setRGB(x-minX, y-minY, color(r, i, 360, false, 2/3f)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
return image; |
|||
} |
|||
} |
|||
private int color(double r0, double i0, int max, boolean straight, float shift) { |
|||
int n = -1; |
|||
double r=0, i=0, r2=0, i2=0; |
|||
do { |
|||
i = r*(i+i) + i0; |
|||
r = r2-i2 + r0; |
|||
r2 = r*r; |
|||
i2 = i*i; |
|||
} |
|||
} |
|||
while (++n < max && r2 + i2 < 4); |
|||
return n == max ? 0 : HSBtoRGB(shift + (float) (straight ? n : max-n) / max /* * 11/12f + (straight?0:1)/12f*/, 1, 1); |
|||
} |
|||
} |
|||
}</lang> |
}</lang> |
||