In SwiftUI I made a view.
The input of data for lensFocalLength comes via a slider or a stepper.
The idea is that the user changes the value and the next time he opens the view, his last used data is shown.
For this method I used the UserDefaults method. But it is not consistent. When user changes the value to for example 100 mm, the next time the view is opened it shows 98 of 105.
This is the code:
import SwiftUI
import Foundation
struct Calc2View: View {
@State private var lensFocalLength: Double
let sensorWidth = 36.0 // Full frame sensor width
init() {
_lensFocalLength = State(initialValue: UserDefaults.standard.double(forKey: "selectedLens") != 0 ? UserDefaults.standard.double(forKey: "selectedLens") : 50.0)
}
var body: some View {
NavigationView {
ScrollView {
VStack {
//Color.clear.frame(height: 10)
HStack{
Text("Camera input")
.font(.headline)
.fontWeight(.bold)
Spacer()
}
Divider()
VStack{
HStack {
Text("Lens")
.font(.headline)
.multilineTextAlignment(.leading)
Spacer()
Text("\(lensFocalLength, specifier: "%.0f") mm")
Spacer()
Stepper("", value: $lensFocalLength, in: 1...1000)
}
HStack {
Slider(value: $lensFocalLength, in: 10...1000, step: 1)
.accentColor(.blue)
}
}
.onChange(of: lensFocalLength) { newValue, _ in
UserDefaults.standard.set(newValue, forKey: "selectedLens")
}
if lensFocalLength > 0 {
let fov = 2 * atan(sensorWidth / (2 * lensFocalLength)) * (180 / .pi) // New formula
let humanFOV = 200.0
let fovealFOV = 120.0
let nikonSensorWidth = 23.6
let canonSensorWidth = 22.3
let microFourThirdsSensorWidth = 17.3
let nikonFOV = 2 * atan(nikonSensorWidth / (2 * lensFocalLength)) * (180 / .pi)
let canonFOV = 2 * atan(canonSensorWidth / (2 * lensFocalLength)) * (180 / .pi)
let microFourThirdsFOV = 2 * atan(microFourThirdsSensorWidth / (2 * lensFocalLength)) * (180 / .pi)
let nikonEquivalentFocalLength = lensFocalLength / 1.5
let canonEquivalentFocalLength = lensFocalLength / 1.6
let microFourThirdsEquivalentFocalLength = lensFocalLength / 2.0
VStack(alignment: .leading) {
Divider()
Color.clear.frame(height: 5)
VStack(alignment: .leading){
Text("Lens Field of View:")
.font(.headline)
.fontWeight(.bold)
HStack {
Text("FullFrame")
Spacer()
Text("\(fov, specifier: "%.1f") degrees")
}
HStack {
Text("APS-C")
Spacer()
Text("\(nikonFOV, specifier: "%.1f") degrees")
}
HStack {
Text("APS-C Canon")
Spacer()
Text("\(canonFOV, specifier: "%.1f") degrees")
}
HStack {
Text("Micro 4/3rd")
Spacer()
Text("\(microFourThirdsFOV, specifier: "%.1f") degrees")
}
Divider()
Color.clear.frame(height: 5)
Text("Equivalent lens:")
.font(.headline)
.fontWeight(.bold)
HStack {
Text("Full Frame")
Spacer()
Text("\(lensFocalLength, specifier: "%.0f") mm")
}
HStack {
Text("APS-C")
Spacer()
Text("\(nikonEquivalentFocalLength, specifier: "%.0f") mm")
}
HStack {
Text("APS-C Canon")
Spacer()
Text("\(canonEquivalentFocalLength, specifier: "%.0f") mm")
}
HStack {
Text("Micro 4/3rd")
Spacer()
Text("\(microFourThirdsEquivalentFocalLength, specifier: "%.0f") mm")
}
Divider()
Color.clear.frame(height: 5)
Text("Full Frame Field of View:")
.font(.headline)
.fontWeight(.bold)
Color.clear.frame(height: 5)
}
}
//.padding(.bottom)
VStack {
ZStack {
FOVTriangle(fov: humanFOV)
.fill(Color.green.opacity(0.5))
FOVTriangle(fov: fovealFOV)
.fill(Color.blue.opacity(0.5))
FOVTriangle(fov: fov)
.fill(Color.pink.opacity(1.0))
}
.frame(height: 200)
.frame(width: 200)
Image(systemName: "camera") // Add SF Symbol
.font(.largeTitle)
//.padding(.top, 20)
Spacer()
HStack{
Image(systemName: "square.fill")
.foregroundColor(.green)
.opacity(0.5)
.font(.system(size: 20))
Text("FoV both eyes")
Spacer()
Image(systemName: "square.fill")
.foregroundColor(.red)
.opacity(1.0)
.font(.system(size: 20))
Text("Lens")
Spacer()
HStack{
Image(systemName: "square.fill")
.foregroundColor(.blue)
.opacity(0.5)
.font(.system(size: 20))
Text("Binocular")
}
}
}
//.offset(y: 100) // Move the VStack 30% lower
} else {
Text("Please enter a valid focal length")
}
}
.navigationTitle("Field of View")
.navigationBarTitleDisplayMode(.inline)
.padding()
}
.navigationViewStyle(.stack)
}
}
}
struct FOVTriangle: Shape {
var fov: Double
func path(in rect: CGRect) -> Path {
var path = Path()
let radians = fov * (.pi / 180.0)
let height = Double(rect.height) / 3.1
let width = tan(radians / 2) * height / 3.1
let startPoint = CGPoint(x: rect.midX, y: rect.maxY)
let leftPoint = CGPoint(x: rect.midX - CGFloat(width), y: 0)
let rightPoint = CGPoint(x: rect.midX + CGFloat(width), y: 0)
path.move(to: startPoint)
path.addLine(to: leftPoint)
path.addLine(to: rightPoint)
path.addLine(to: startPoint)
return path
}
}
#Preview {
Calc2View()
}
everything :-) No result unfortunately