Skip to content

Commit

Permalink
Working build
Browse files Browse the repository at this point in the history
  • Loading branch information
Gary Kerr committed Jun 15, 2021
1 parent 85c2270 commit f0edae6
Show file tree
Hide file tree
Showing 16 changed files with 846 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
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 Sources/MandelbrotEngine/ColourMaps/ColourMapFactory.swift
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 Sources/MandelbrotEngine/ColourMaps/ColourMapProtocol.swift
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)
}
}
29 changes: 29 additions & 0 deletions Sources/MandelbrotEngine/ColourMaps/GreyScale.swift
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 Sources/MandelbrotEngine/ColourMaps/ManyColourGradient.swift
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 })
}
}
77 changes: 77 additions & 0 deletions Sources/MandelbrotEngine/ColourMaps/SmoothScale.swift
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)))
}
}
83 changes: 83 additions & 0 deletions Sources/MandelbrotEngine/ColourMaps/SmoothTest.swift
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)))
}
}
29 changes: 29 additions & 0 deletions Sources/MandelbrotEngine/ColourMaps/YellowScale.swift
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()
}
}
34 changes: 34 additions & 0 deletions Sources/MandelbrotEngine/ComplexNumber.swift
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)
}
}
Loading

0 comments on commit f0edae6

Please sign in to comment.