Table of Contents
1 Program purpose
The purpose of the program is to provide a flexible way of estimating the correct settings of a photographic speed light and DSLR camera for a simple scene and likewise estimate the correct construction of a scene given the settings of a speedlight and camera.
1.1 Program Outline
"off-camera-light.st" "Estimates the setting for using a camera and speed light or conversely estimates the necessary scene parameters based on camera and speed light settings" Namespace current: OffCameraLight [ <<light-value>> <<camera>> <<light>> <<subject>> <<scene>> ]
Perhaps the one of the interesting features of this program is that it uses GNU Smalltalk's namespaces. The reason I find it interesting is that literate programming allows the use of namespace while still writing code that is right justified in the editor. By which I mean that the logical nesting of namespace contents wrapped by [...]
does not result in redundant indentation when editing the code blocks. For me, having code indented off the left margin when the context for the indentation is irrelevant is ergonomically poor. It bothered me when writing Racket Modules and I prefer Common Lisp's (in-package ...)
declarative syntax to explicit nesting. YMMV.
1.2 Base formula
Working distance at full illumination equals light rating divided by f-stop at ISO 100.
workingdistance = (rating * (log2(ISO/100) + 1)) / f-stop.
rating = base power / power setting
1.3 Constraint Network Approach
Given that the goal is to establish a two way relationship circle light <-> camera <-> scene <-> light this seems like a problem for constraint networks.
2 Objects?
2.1 Light
Object subclass: Light [ "A class to model a speedlight state." | rating power_setting | guide_number [ "Get the rating of a speedlight." ^rating. ] guide_number: aDistance [ "Set the rating of a speedlight." rating := aDistance. ] power [ "Get the power setting of the speedlight." ^power_setting. ] power: aNumber [ "Get the power setting of the speedlight." power_setting := aNumber. ] ]
2.2 Camera
Object subclass: Camera [ "The basis for variable names is Manual of Photography 10th edition. n is relative aperture t is shutter speed s is sensitivity based" | n t s | <comment: 'A class for describing the state of a camera.'> <<camera-init>> aperture [ "Get the aperture value." ^n. ] aperture: stop [ "Set the camera's aperture." n := stop. ] shutter [ "Get camera's shutter speed." ^t. ] shutter: time [ "Set camera's shutter speed." t := time. ] iso [ "Get camera's sensitivity setting." ^s. ] iso: sensitivity [ "Set camera's sensitivity setting." s := sensitivity. ] eV [ | sunny16Ev aperture shutter iso rawEv | "Calculate the Exposure Value." sunny16Ev := 8. aperture := n squared log: 2. shutter := 100 / (1/t) log: 2. iso := (s / 100) log: 2. rawEv := aperture + shutter + iso. ^'Not yet implemented'. ] sunny16 [ "Calculate the number of stops away from Sunny 16 settings." ^eV - 15. ] ]
Create and initialize a camera. Code ends with yourself
to return the object rather than the value of the last expression.
Camera class >> aperture: stop shutter: time iso: sensitivity [ ^(self new) aperture: stop; shutter: time; iso: sensitivity; yourself. ]
2.3 Scene
A scene for our purpose has a camera, speedlight, a subject, and a light value.
Object subclass: Scene [ | subject lV foreground background | "A container for all the components of a photograph (sort of)." ]
2.3.1 Light Value
The light value in a scene is a scalar of the reflected light reaching the camera (on average). In this project it is implemented as a "global" variable of the namespace OffCameraLight
.
"The values and descriptions are from http://www.crakephoto.com/reference/index.html" <comment: 'A dictionary associating light values with scene descriptions'> LightValue := Dictionary new. LightValue at: 17 put: 'Rarely seen in nature'. LightValue at: 16 put: 'Bright sunlight off of sand or snow'. LightValue at: 15 put: 'Bright hazy sunlight'. LightValue at: 14 put: 'Weak hazy sunlight'. LightValue at: 13 put: 'Bright cloudy day'. LightValue at: 12 put: 'Overcast day'. LightValue at: 11 put: 'Shade on a bright day or during sunrise/set'. LightValue at: 10 put: 'Dusk or dawn'. LightValue at: 9 put: 'Late dusk or early dawn'. LightValue at: 8 put: 'Times square at night '. LightValue at: 7 put: 'Brightly lit street '. LightValue at: 6 put: 'Bright interior '. LightValue at: 5 put: 'Average interior or auditorium'. LightValue at: 4 put: 'Christmas or candle lights'. LightValue at: 3 put: 'Fireworks (emitted)'. LightValue at: 2 put: 'Lightning from a distance (emitted)'. LightValue at: 1 put: 'City skyline at night (emitted)'. LightValue at: 0 put: 'Dim ambient light'. LightValue at: -1 put: 'Really dim ambient light'. LightValue at: -2 put: 'Full moon off of sand or snow'. LightValue at: -3 put: 'Full moon'. LightValue at: -4 put: 'Half moon'. LightValue at: -5 put: 'Crescent moon'. LightValue at: -6 put: 'Starlight'.
2.3.2 Subject
Object subclass: Subject [ | d | "A class to describe a photographic subject." distance [ "Get the distance to a subject." ^d. ] distance: aNumber [ "Set the distance to a subject." d := aNumber. ] ]
2.3.3 Foreground
2.3.4 Background
2.4 World TODO
Object subclass: world [ | scene camera light | "A class to simulate a photographic environment." ]