RosettaCodeData/Task/Mandelbrot-set/Swift/mandelbrot-set.swift
2023-07-01 13:44:08 -04:00

88 lines
1.9 KiB
Swift

import Foundation
import Numerics
import QDBMP
public typealias Color = (red: UInt8, green: UInt8, blue: UInt8)
public class BitmapDrawer {
public let imageHeight: Int
public let imageWidth: Int
var grid: [[Color?]]
private let bmp: OpaquePointer
public init(height: Int, width: Int) {
self.imageHeight = height
self.imageWidth = width
self.grid = [[Color?]](repeating: [Color?](repeating: nil, count: height), count: width)
self.bmp = BMP_Create(UInt(width), UInt(height), 24)
checkError()
}
deinit {
BMP_Free(bmp)
}
private func checkError() {
let err = BMP_GetError()
guard err == BMP_STATUS(0) else {
fatalError("\(err)")
}
}
public func save(to path: String = "~/Desktop/out.bmp") {
for x in 0..<imageWidth {
for y in 0..<imageHeight {
guard let color = grid[x][y] else { continue }
BMP_SetPixelRGB(bmp, UInt(x), UInt(y), color.red, color.green, color.blue)
checkError()
}
}
(path as NSString).expandingTildeInPath.withCString {s in
BMP_WriteFile(bmp, s)
}
}
public func setPixel(x: Int, y: Int, to color: Color?) {
grid[x][y] = color
}
}
let imageSize = 10_000
let canvas = BitmapDrawer(height: imageSize, width: imageSize)
let maxIterations = 256
let cxMin = -2.0
let cxMax = 1.0
let cyMin = -1.5
let cyMax = 1.5
let scaleX = (cxMax - cxMin) / Double(imageSize)
let scaleY = (cyMax - cyMin) / Double(imageSize)
for x in 0..<imageSize {
for y in 0..<imageSize {
let cx = cxMin + Double(x) * scaleX
let cy = cyMin + Double(y) * scaleY
let c = Complex(cx, cy)
var z = Complex(0.0, 0.0)
var i = 0
for t in 0..<maxIterations {
if z.magnitude > 2 {
break
}
z = z * z + c
i = t
}
canvas.setPixel(x: x, y: y, to: Color(red: UInt8(i), green: UInt8(i), blue: UInt8(i)))
}
}
canvas.save()