Skip to content

Instantly share code, notes, and snippets.

@yay
Created April 9, 2018 11:42
Show Gist options
  • Save yay/5f576bb6c2ea7f70ff74dbea1fcf4c13 to your computer and use it in GitHub Desktop.
Save yay/5f576bb6c2ea7f70ff74dbea1fcf4c13 to your computer and use it in GitHub Desktop.
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