Last active
June 5, 2024 10:03
-
-
Save theoknock/0bf6b2ccaba4d463524fc985f428d549 to your computer and use it in GitHub Desktop.
"Circular distributions can be used even when the variables concerned are not explicitly angles: the main consideration is that there is not usually any real distinction between events occurring at the opposite ends of the range, and the division of the range could notionally be made at any point." https://en.wikipedia.org/wiki/Circular_distribu…
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
import Foundation | |
import SwiftUI | |
import Combine | |
import Observation | |
struct ContentView: View { | |
@State private var randoms: LatticeCircularDistributor = LatticeCircularDistributor(boundLower: 0.3125, boundUpper: 0.3125, threshholdLeft: 0.25, threshholdRight: 0.25) | |
var body: some View { | |
Spacer() | |
VStack { | |
Spacer() | |
Text("\(randoms.description())") | |
.font(.body).monospacedDigit() | |
Spacer() | |
Button(action: { | |
randoms.distributeRandoms(randoms: &randoms.randoms) | |
}, label: { | |
Text("Generate randoms") | |
.padding() | |
.border(.blue, width: 1.0) | |
}) | |
Spacer() | |
} | |
.onAppear { | |
randoms.distributeRandoms(randoms: &randoms.randoms) | |
} | |
Spacer() | |
} | |
} | |
#Preview { | |
ContentView() | |
.preferredColorScheme(.dark) | |
} |
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
import Foundation | |
import SwiftUI | |
import Combine | |
import Observation | |
@Observable class LatticeCircularDistributor { | |
var boundLower: Float64 | |
var boundUpper: Float64 | |
var randoms: [Float64] = [Float64.zero, Float64.zero] | |
var threshholdLeft: Float64 | |
var threshholdRight: Float64 | |
func scaledAngle(scale: Float64) -> Float64 { | |
return Float64(abs(360.0 * scale)) | |
} | |
func offsetByDegrees(startAngle: Float64, offsetDegrees: Float64) -> Float64 { | |
return Float64((startAngle + offsetDegrees).truncatingRemainder(dividingBy: 360.0)) | |
} | |
// func offsetAngle(startAngle: Float64, offsetDegrees: Float64) -> Float64 { | |
// let radians = (startAngle + offsetDegrees) * .pi / 180.0 | |
// let sinValue = sin(radians) | |
// let cosValue = cos(radians) | |
// let angle = atan2(sinValue, cosValue) * 180.0 / .pi | |
// return angle | |
// } | |
func offsetAngle(startAngle: Float64, offsetDegrees: Float64) -> Float64 { | |
let radians = (startAngle + offsetDegrees) * .pi / 180.0 | |
let sinValue = sin(radians) | |
let cosValue = cos(radians) | |
let angle = atan2(sinValue, cosValue) * 180.0 / .pi | |
let wrappedAngle = angle + 360.0 * floor((360.0 - angle) / 360.0) | |
return wrappedAngle | |
} | |
private func wrapAngle(_ angle: Double) -> Double { | |
let wrapped = angle.truncatingRemainder(dividingBy: 360) | |
return wrapped >= 0 ? wrapped : wrapped + 360 | |
} | |
func description() -> String { | |
return String("\(randoms[0])°\t\t\(randoms[1])°") | |
} | |
func distributeRandoms(randoms: inout [Float64]) -> (Void) { | |
let lowerRangeBoundary: Float64 = scaledAngle(scale: 0.0625) | |
let upperRangeBoundary: Float64 = scaledAngle(scale: 0.9375) | |
print("lowerRangeBoundary == \(lowerRangeBoundary)") | |
print("upperRangeBoundary == \(upperRangeBoundary)") | |
let firstRandom: Float64 = Float64.random(in: lowerRangeBoundary ... upperRangeBoundary) | |
print("firstRandom == \(firstRandom)") | |
let lowerRandomThreshold: Float64 = scaledAngle(scale: 0.0625) | |
let upperRandomThreshold: Float64 = scaledAngle(scale: 0.0625) | |
print("lowerRandomThreshold == \(lowerRandomThreshold)") | |
print("upperRandomThreshold == \(upperRandomThreshold)") | |
// get the actual lowerRangeBoundary and the relative lowerRandomThreshold and use offset func to calculate new lower bounds | |
let secondRandomLowerRange: Float64 = Float64(offsetAngle(startAngle: lowerRangeBoundary, offsetDegrees: lowerRandomThreshold)) | |
let secondRandomUpperRange: Float64 = Float64(offsetAngle(startAngle: upperRangeBoundary, offsetDegrees: -upperRandomThreshold)) | |
print("secondRandomLowerRange == \(secondRandomLowerRange)") | |
print("secondRandomUpperRange == \(secondRandomUpperRange)") | |
let nextRandom: Float64 = Float64.random(in: secondRandomLowerRange ... secondRandomUpperRange) | |
print("nextRandom == \(nextRandom)") | |
let adjustedSecondRandom: Float64 = Float64(offsetAngle(startAngle: nextRandom, offsetDegrees: firstRandom)) | |
print("adjustedSecondRandom == \(adjustedSecondRandom)") | |
randoms = [firstRandom, nextRandom] | |
} | |
init(boundLower: Float64, boundUpper: Float64, threshholdLeft: Float64, threshholdRight: Float64) { | |
self.boundLower = boundLower | |
self.boundUpper = boundUpper | |
self.threshholdLeft = threshholdLeft | |
self.threshholdRight = threshholdRight | |
distributeRandoms(randoms: &self.randoms) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment