-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Gary Kerr
committed
Jun 15, 2021
1 parent
85c2270
commit f0edae6
Showing
16 changed files
with
846 additions
and
1 deletion.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
# MandelbrotEngine | ||
|
||
A description of this package. | ||
A Mandelbrot set generator. |
26 changes: 26 additions & 0 deletions
26
Sources/MandelbrotEngine/ColourMaps/ColourMapFactory.swift
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// | ||
// ColourMapFactory.swift | ||
// MandelbrotApp | ||
// | ||
// Created by gary on 13/09/2018. | ||
// Copyright © 2018 Gary Kerr. All rights reserved. | ||
// | ||
|
||
struct ColourMapFactory { | ||
static var maps: [ColourMapProtocol] { | ||
return [ | ||
GreyScale(numberOfGreys: 200), | ||
YellowScale(numberOfYellows: 100), | ||
SmoothScale(), | ||
ManyColourGradient( | ||
n: 100, | ||
colours: (r: 255, g: 0, b: 0), (r: 255, g: 255, b: 0) | ||
), | ||
ManyColourGradient( | ||
n: 70, | ||
colours: (r: 255, g: 0, b: 0), (r: 255, g: 255, b: 0), (r: 255, g: 255, b: 255) | ||
), | ||
SmoothTest() | ||
] | ||
} | ||
} |
56 changes: 56 additions & 0 deletions
56
Sources/MandelbrotEngine/ColourMaps/ColourMapProtocol.swift
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// | ||
// ColourMapProtocol.swift | ||
// Mandelbrot | ||
// | ||
// Created by gary on 29/04/2017. | ||
// Copyright © 2017 Gary Kerr. All rights reserved. | ||
// | ||
|
||
import CoreGraphics | ||
|
||
|
||
protocol ColourMapProtocol { | ||
typealias RGB = (r: UInt8, g: UInt8, b: UInt8) | ||
|
||
var id: String { get } | ||
var title: String { get } | ||
var blackPixel: Pixel { get } | ||
var pixels: [Pixel] { get } | ||
func pixel(from test: MandelbrotSetPoint.Test) -> Pixel | ||
} | ||
|
||
|
||
extension ColourMapProtocol { | ||
var id: String { title } | ||
|
||
|
||
func pixel(from test: MandelbrotSetPoint.Test) -> Pixel { | ||
switch test { | ||
case .inSet: | ||
return blackPixel | ||
case .notInSet(let iterations, _): | ||
return pixels[iterations % pixels.count] | ||
} | ||
} | ||
|
||
|
||
static func gradient(from: RGB, to: RGB, n: Int) -> [Pixel] { | ||
let dr = diff(m: to.r, n: from.r)/Double(n) | ||
let dg = diff(m: to.g, n: from.g)/Double(n) | ||
let db = diff(m: to.b, n: from.b)/Double(n) | ||
var (r, g, b) = (Double(from.r), Double(from.g), Double(from.b)) | ||
var pixels: [Pixel] = [] | ||
for _ in 0 ..< n { | ||
pixels.append(Pixel(r: UInt8(r), g: UInt8(g), b: UInt8(b))) | ||
r += dr | ||
g += dg | ||
b += db | ||
} | ||
return pixels | ||
} | ||
|
||
|
||
static func diff(m: UInt8, n: UInt8) -> Double { | ||
return Double(m) - Double(n) | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// | ||
// GreyScale.swift | ||
// Mandelbrot | ||
// | ||
// Created by gary on 29/04/2017. | ||
// Copyright © 2017 Gary Kerr. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
struct GreyScale: ColourMapProtocol { | ||
|
||
internal let title = "Grey scale" | ||
internal let pixels: [Pixel] | ||
internal let blackPixel = Pixel(r: 0, g: 0, b: 0) | ||
private let pixelMin = 20 | ||
private let pixelMax = 255 | ||
|
||
|
||
init(numberOfGreys: Int) { | ||
var pixelList: [Pixel] = [] | ||
let step = max(Int(Double(pixelMax - pixelMin)/Double(numberOfGreys)), 1) | ||
for i in stride(from: pixelMin, to: pixelMax, by: step) { | ||
let j = UInt8(i) | ||
pixelList.append(Pixel(r: j, g: j, b: j)) | ||
} | ||
pixels = pixelList + pixelList.reversed() | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
Sources/MandelbrotEngine/ColourMaps/ManyColourGradient.swift
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// | ||
// ManyColourGradient.swift | ||
// Mandelbrot | ||
// | ||
// Created by gary on 06/05/2017. | ||
// Copyright © 2017 Gary Kerr. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
struct ManyColourGradient: ColourMapProtocol { | ||
|
||
var title: String { | ||
return "Many colour gradient: \(colourCount)" | ||
} | ||
|
||
internal let pixels: [Pixel] | ||
internal let blackPixel = Pixel(r: 0, g: 0, b: 0) | ||
|
||
private let colourCount: Int | ||
|
||
|
||
init(n: Int, colours: RGB...) { | ||
colourCount = colours.count | ||
var secondColours = Array(colours[1 ... colours.count - 1]) | ||
secondColours.append(colours.first!) | ||
pixels = zip(colours, secondColours) | ||
.map({ ManyColourGradient.gradient(from: $0, to: $1, n: n) }) | ||
.reduce([], { x, y in x + y }) | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
// | ||
// SmoothScale.swift | ||
// Mandelbrot | ||
// | ||
// Created by gary on 02/05/2017. | ||
// Copyright © 2017 Gary Kerr. All rights reserved. | ||
// | ||
// http://stackoverflow.com/questions/369438/smooth-spectrum-for-mandelbrot-set-rendering | ||
|
||
import Foundation | ||
|
||
struct SmoothScale: ColourMapProtocol { | ||
|
||
static let (h1, s1, v1): (CGFloat, CGFloat, CGFloat) = (0.0, 1.0, 1.0) | ||
static let (h2, s2, v2): (CGFloat, CGFloat, CGFloat) = (360.0, 1.0, 1.0) | ||
|
||
let nColours = 500 | ||
|
||
internal let title = "Smooth scale" | ||
internal let blackPixel = Pixel(r: 0, g: 0, b: 0) | ||
let pixels: [Pixel] | ||
|
||
|
||
init() { | ||
pixels = SmoothScale.makePixels(nColours: nColours) | ||
} | ||
} | ||
|
||
|
||
// MARK: - Private | ||
|
||
private extension SmoothScale { | ||
private static func makePixels(nColours: Int) -> [Pixel] { | ||
var pixels: [Pixel] = [] | ||
for i in stride(from: 0.0, through: 1.0, by: 1.0/Double(nColours)) { | ||
let h = (h2 - h1) * CGFloat(i) + h1 | ||
let s = (s2 - s1) * CGFloat(i) + s1 | ||
let v = (v2 - v1) * CGFloat(i) + v1 | ||
let (r, g, b) = hsv_to_rgb(h: h, s: s, v: v) | ||
|
||
|
||
// let colour = UIColor(hue: h, saturation: s, brightness: v, alpha: 1.0) | ||
// let (r, g, b, _) = colour.rgbaInt | ||
|
||
pixels.append(Pixel(r: r, g: g, b: b)) | ||
} | ||
return pixels | ||
} | ||
|
||
|
||
private static func hsv_to_rgb(h: CGFloat, s: CGFloat, v: CGFloat) -> (r: UInt8, g: UInt8, b: UInt8) { | ||
let c = s * v | ||
let hp = h / 60 | ||
let x = c * (1 - abs(hp.truncatingRemainder(dividingBy: 2) - 1)) | ||
let r1: CGFloat | ||
let g1: CGFloat | ||
let b1: CGFloat | ||
switch hp { | ||
case 0...1: | ||
(r1, g1, b1) = (c, x, 0) | ||
case 1...2: | ||
(r1, g1, b1) = (x, c, 0) | ||
case 2...3: | ||
(r1, g1, b1) = (0, c, x) | ||
case 3...4: | ||
(r1, g1, b1) = (0, x, c) | ||
case 4...5: | ||
(r1, g1, b1) = (x, 0, c) | ||
case 5...6: | ||
(r1, g1, b1) = (c, 0, x) | ||
default: | ||
(r1, g1, b1) = (0, 0, 0) | ||
} | ||
let m = v - c | ||
return (UInt8(256 * (r1 + m)), UInt8(256 * (g1 + m)), UInt8(256 * (b1 + m))) | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
// | ||
// SmoothTest.swift | ||
// MandelbrotApp | ||
// | ||
// Created by gary on 16/09/2018. | ||
// Copyright © 2018 Gary Kerr. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
struct SmoothTest: ColourMapProtocol { | ||
private let log2Value: Double = log(2) | ||
private let log4Value: Double = log(4) | ||
|
||
internal let title = "Smooth Test" | ||
internal let blackPixel = Pixel(r: 0, g: 0, b: 0) | ||
let pixels: [Pixel] = [] | ||
|
||
|
||
func pixel(from test: MandelbrotSetPoint.Test) -> Pixel { | ||
switch test { | ||
case .inSet: | ||
return blackPixel | ||
case .notInSet(let N, let zN): | ||
return makePixel(N: N, zN: zN) | ||
// return makePixel2(N: N, zN: zN) | ||
} | ||
} | ||
} | ||
|
||
|
||
private extension SmoothTest { | ||
func makePixel(N: Int, zN: ComplexNumber) -> Pixel { | ||
let modulus = sqrt(zN.modulus()) | ||
let mu = Double(N + 1) - log(log(modulus))/log2Value | ||
// var hue = CGFloat(0.95 + 20.0 * mu) // adjust to make it prettier | ||
var hue = CGFloat(mu) | ||
while hue > 1 { | ||
hue -= 1 | ||
} | ||
while hue < 0.0 { | ||
hue += 1 | ||
} | ||
let (r, g, b) = hsv_to_rgb(h: hue, s: 0.8, v: 1) | ||
return Pixel(r: r, g: g, b: b) | ||
} | ||
|
||
|
||
func makePixel2(N: Int, zN: ComplexNumber) -> Pixel { | ||
let log_zn = log(zN.modulus()) | ||
let mu = Double(N + 1) - log(log_zn/log2Value)/log2Value | ||
print(mu) | ||
return blackPixel | ||
} | ||
|
||
|
||
func hsv_to_rgb(h: CGFloat, s: CGFloat, v: CGFloat) -> (r: UInt8, g: UInt8, b: UInt8) { | ||
let c = s * v | ||
let hp = h / 60 | ||
let x = c * (1 - abs(hp.truncatingRemainder(dividingBy: 2) - 1)) | ||
let r1: CGFloat | ||
let g1: CGFloat | ||
let b1: CGFloat | ||
switch hp { | ||
case 0...1: | ||
(r1, g1, b1) = (c, x, 0) | ||
case 1...2: | ||
(r1, g1, b1) = (x, c, 0) | ||
case 2...3: | ||
(r1, g1, b1) = (0, c, x) | ||
case 3...4: | ||
(r1, g1, b1) = (0, x, c) | ||
case 4...5: | ||
(r1, g1, b1) = (x, 0, c) | ||
case 5...6: | ||
(r1, g1, b1) = (c, 0, x) | ||
default: | ||
(r1, g1, b1) = (0, 0, 0) | ||
} | ||
let m = v - c | ||
return (UInt8(256 * (r1 + m)), UInt8(256 * (g1 + m)), UInt8(256 * (b1 + m))) | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// | ||
// YellowScale.swift | ||
// Mandelbrot | ||
// | ||
// Created by gary on 29/04/2017. | ||
// Copyright © 2017 Gary Kerr. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
struct YellowScale: ColourMapProtocol { | ||
|
||
internal let title = "Yellow scale" | ||
internal let pixels: [Pixel] | ||
internal let blackPixel = Pixel(r: 0, g: 0, b: 0) | ||
private let pixelMin = 20 | ||
private let pixelMax = 255 | ||
|
||
|
||
init(numberOfYellows: Int) { | ||
var pixelList: [Pixel] = [] | ||
let step = max(Int(Double(pixelMax - pixelMin)/Double(numberOfYellows)), 1) | ||
for i in stride(from: pixelMin, to: pixelMax, by: step) { | ||
let j = UInt8(i) | ||
pixelList.append(Pixel(r: j, g: j, b: 0)) | ||
} | ||
pixels = pixelList + pixelList.reversed() | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// | ||
// ComplexNumber.swift | ||
// Mandelbrot | ||
// | ||
// Created by gary on 29/04/2017. | ||
// Copyright © 2017 Gary Kerr. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
struct ComplexNumber { | ||
let x: Double | ||
let y: Double | ||
|
||
|
||
func modulus() -> Double { | ||
return x*x + y*y | ||
} | ||
|
||
|
||
static func + (lhs: ComplexNumber, rhs: ComplexNumber) -> ComplexNumber { | ||
return ComplexNumber(x: lhs.x + rhs.x, y: lhs.y + rhs.y) | ||
} | ||
|
||
|
||
static func - (lhs: ComplexNumber, rhs: ComplexNumber) -> ComplexNumber { | ||
return ComplexNumber(x: lhs.x - rhs.x, y: lhs.y - rhs.y) | ||
} | ||
|
||
|
||
static func * (lhs: ComplexNumber, rhs: ComplexNumber) -> ComplexNumber { | ||
return ComplexNumber(x: lhs.x * rhs.x - lhs.y * rhs.y, y: lhs.x * rhs.y + lhs.y * rhs.x) | ||
} | ||
} |
Oops, something went wrong.