Created
April 9, 2018 11:42
-
-
Save yay/5f576bb6c2ea7f70ff74dbea1fcf4c13 to your computer and use it in GitHub Desktop.
This file contains 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
package com.vitalyk.kotlin.sandbox | |
import javafx.application.Application | |
import javafx.geometry.Insets | |
import javafx.geometry.Pos | |
import javafx.scene.Scene | |
import javafx.scene.canvas.Canvas | |
import javafx.scene.control.Button | |
import javafx.scene.control.Label | |
import javafx.scene.control.Slider | |
import javafx.scene.layout.HBox | |
import javafx.scene.layout.VBox | |
import javafx.scene.paint.Color | |
import javafx.stage.Stage | |
class MandelbrotApp : Application() { | |
override fun start(primaryStage: Stage) { | |
val side = 600.0 | |
val canvas = Canvas(side, side) | |
val vbox = VBox() | |
val toolbar = HBox().apply { | |
spacing = 10.0 | |
padding = Insets(10.0) | |
alignment = Pos.CENTER_LEFT | |
} | |
val fidelityLabel = Label() | |
fun updateFidelityLabel(slider: Slider) { | |
fidelityLabel.text = "Max Iterations: ${slider.value.toInt()}" | |
} | |
val fidelitySlider = Slider().apply { | |
min = 8.0 | |
max = 512.0 | |
value = 256.0 | |
minWidth = 200.0 | |
valueProperty().addListener { _, _, _ -> | |
updateFidelityLabel(this) | |
} | |
} | |
updateFidelityLabel(fidelitySlider) | |
val renderBtn = Button().apply{ | |
text = "Render" | |
setOnAction { | |
render(canvas, fidelitySlider.value.toInt()) | |
} | |
} | |
toolbar.children.apply { | |
add(renderBtn) | |
add(fidelitySlider) | |
add(fidelityLabel) | |
} | |
vbox.children.apply { | |
add(toolbar) | |
add(canvas) | |
} | |
val scene = Scene(vbox, side, side) | |
primaryStage.apply { | |
this.scene = scene | |
title = "Mandelbrot" | |
show() | |
} | |
render(canvas) | |
} | |
} | |
fun render(canvas: Canvas, maxIterations: Int = 256) { | |
val w = canvas.width.toInt() | |
val h = canvas.height.toInt() | |
val pw = canvas.graphicsContext2D.pixelWriter | |
val tx = -.6 * w | |
val ty = -.5 * h | |
val maxIterationsDbl = maxIterations.toDouble() | |
for (x in 0 until w) { | |
for (y in 0 until h) { | |
var re = x.toDouble() + tx | |
var im = y.toDouble() + ty | |
re *= 0.01 | |
im *= 0.01 | |
val i = mandelbrot(re, im, maxIterations) | |
if (i != null) { | |
val c = (maxIterations - i) / maxIterationsDbl | |
pw.setColor(x, y, Color(c, c, c, 1.0)) | |
} else | |
pw.setColor(x, y, Color.BLACK) | |
} | |
} | |
} | |
fun mandelbrot(cRe: Double, cIm: Double, maxIterations: Int): Int? { | |
tailrec fun iterate(zRe: Double, zIm: Double, iterations: Int): Int? = | |
when { | |
iterations == maxIterations -> null | |
Math.hypot(zRe, zIm) > 2.0 -> iterations | |
else -> { | |
var re = zRe * zRe - zIm * zIm | |
var im = 2 * zRe * zIm | |
re += cRe | |
im += cIm | |
iterate(re, im, iterations + 1) | |
} | |
} | |
return iterate(0.0, 0.0, 0) | |
} | |
fun main(args: Array<String>) { | |
Application.launch(MandelbrotApp::class.java, *args) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment