optical 0 → 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.markdown +52 -8
- data/Rakefile +8 -0
- data/lib/optical.rb +4 -1
- data/lib/optical/lens.rb +58 -0
- data/lib/optical/plano_convex_lens.rb +25 -0
- data/lib/optical/system.rb +47 -0
- data/optical.gemspec +2 -2
- data/test/optical/lens.rb +28 -0
- data/test/optical/plano_convex_lens.rb +26 -0
- data/test/optical/system.rb +60 -0
- metadata +12 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4f4400f4aa624b50b95186d0ead6ddb5a1c033f9
|
4
|
+
data.tar.gz: b0bed9445d1164a994190e77dcb6192ebd19f119
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0014fcd6738e371bb5c03c2d4ccda9dbe22f592faa1513f1696e0749a750920f846b53c6f1a8628dd2be259e04473e5218d32b30aa1443ef8e084564b017086b
|
7
|
+
data.tar.gz: d0ebe9fe8cc259406cf326f617b856d49775fd8fcfd441ca866b6592cd8d96c82dec100105126a53a94f9f6cc3d3d9a77cc53383b214e1221cc55453a2aefae2
|
data/README.markdown
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Optical
|
2
2
|
|
3
|
-
|
3
|
+
Remember that optics class you took in college? Me neither, and that's why I wrote this gem.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -18,12 +18,56 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
|
21
|
+
### Lenses
|
22
22
|
|
23
|
-
|
23
|
+
The optical gem has primitives for modeling generic thin-lenses, as well as more specific lens types.
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
To model a simple thin lens, simply...
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
lens = Optical::Lens.new diameter:12.mm, focal_length:20.mm
|
29
|
+
```
|
30
|
+
|
31
|
+
A Plano-Convex lens is just as easy to make...
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
lens = Optical::Lens.new diameter:12.mm, focal_length:20.mm
|
35
|
+
```
|
36
|
+
|
37
|
+
### Optical Systems
|
38
|
+
|
39
|
+
A simple optical system (no splitters) can be modeled using the familiar `push` syntax.
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
system = Optical::System.new
|
43
|
+
system.push Optical::Lens.new
|
44
|
+
system.push Optical::Lens.new
|
45
|
+
```
|
46
|
+
|
47
|
+
The two lenses in that last example won't have any space between, which is almost
|
48
|
+
never what you want. You can set the distance between them by pushing a special
|
49
|
+
spacer element.
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
system.push Optical::Lens.new
|
53
|
+
system.push Optical::System.spacer(10.mm)
|
54
|
+
system.push Optical::Lens.new
|
55
|
+
```
|
56
|
+
|
57
|
+
or you can simply push any Numeric-like object
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
system.push Optical::Lens.new
|
61
|
+
system.push 10.mm
|
62
|
+
system.push Optical::Lens.new
|
63
|
+
```
|
64
|
+
|
65
|
+
If you have a number of elements that all need the same spacing, you can set a
|
66
|
+
default spacing value before pushing the elements. The default value will be in
|
67
|
+
effect until changed.
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
system.spacing = 10.mm
|
71
|
+
system.push Optical::Lens.new # These two elements will get a 10mm spacer
|
72
|
+
system.push Optical::Lens.new # added between them automatically
|
73
|
+
```
|
data/Rakefile
CHANGED
data/lib/optical.rb
CHANGED
data/lib/optical/lens.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
module Optical
|
2
|
+
# A representation of a simple thin lens
|
3
|
+
# http://en.wikipedia.org/wiki/Lens_(optics)
|
4
|
+
class Lens
|
5
|
+
# @!attribute [r] focal_length
|
6
|
+
# @return [Number] the distance from the principal plane to the focal point
|
7
|
+
attr_reader :focal_length
|
8
|
+
|
9
|
+
def initialize(**options)
|
10
|
+
options.each {|k,v| respond_to?(k) ? instance_variable_set("@#{k}", v) : raise(ArgumentError, "Unknown argument: '#{k}'") }
|
11
|
+
end
|
12
|
+
|
13
|
+
# @!attribute [r] clear_diameter
|
14
|
+
# @return [Number] the diameter of the portion of the {Lens} that meets its stated specifications
|
15
|
+
def clear_diameter
|
16
|
+
@clear_diameter || (2*@clear_radius)
|
17
|
+
end
|
18
|
+
alias :clear_aperture :clear_diameter
|
19
|
+
|
20
|
+
# @!attribute [r] clear_radius
|
21
|
+
# @return [Number] the radius of the portion of the {Lens} that meets its stated specifications
|
22
|
+
def clear_radius
|
23
|
+
@clear_radius || (@clear_diameter && @clear_diameter/2)
|
24
|
+
end
|
25
|
+
|
26
|
+
# @!attribute [r] center_thickness
|
27
|
+
# @return [Number] the thickness of the {Lens} at its center
|
28
|
+
attr_reader :center_thickness
|
29
|
+
|
30
|
+
# @!attribute diameter
|
31
|
+
# @return [Number] the physical diameter of the {Lens}
|
32
|
+
def diameter
|
33
|
+
@diameter || 2*@radius
|
34
|
+
end
|
35
|
+
|
36
|
+
# @!attribute [r] edge_thickness
|
37
|
+
# @return [Number] the thickness of the {Lens} at its edge
|
38
|
+
attr_accessor :edge_thickness
|
39
|
+
|
40
|
+
# @!attribute [r] numerical_aperture
|
41
|
+
# @return [Number] the numerical aperture of the lens, based on clear_radius (if set; otherwise it's based on radius)
|
42
|
+
def numerical_aperture
|
43
|
+
Math.sin(Math.atan2(clear_radius || radius, focal_length))
|
44
|
+
end
|
45
|
+
|
46
|
+
# @!attribute [r] radius
|
47
|
+
# @return [Number] the physical radius of the {Lens}
|
48
|
+
def radius
|
49
|
+
@radius || @diameter/2
|
50
|
+
end
|
51
|
+
|
52
|
+
# @!attribute thickness
|
53
|
+
# @return [Number] the maximum thickness of the {Lens}
|
54
|
+
def thickness
|
55
|
+
[@center_thickness, @edge_thickness].max
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative 'lens'
|
2
|
+
|
3
|
+
module Optical
|
4
|
+
# A representation of a plano convex lens
|
5
|
+
class PlanoConvexLens < Lens
|
6
|
+
# @!attribute radius_of_curvature
|
7
|
+
# @return [Number] the radius of curvature of the optical surface
|
8
|
+
attr_reader :radius_of_curvature
|
9
|
+
|
10
|
+
# @!attribute thickness
|
11
|
+
# @param radius [Number] the distance from the ceterline of the lens
|
12
|
+
# @return [Number] the thickness of the {Lens} at a given distance from the centerline
|
13
|
+
def thickness(_radius=nil, **options)
|
14
|
+
return super() if !_radius && options.empty?
|
15
|
+
|
16
|
+
_radius ||= options[:radius] || (options[:diameter]/2)
|
17
|
+
|
18
|
+
raise ArgumentError, "Requested radius (#{_radius}) is outside of the lens" if _radius > radius
|
19
|
+
|
20
|
+
if _radius && center_thickness && radius_of_curvature
|
21
|
+
center_thickness - radius_of_curvature + Math.sqrt(radius_of_curvature**2 - _radius**2)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Optical
|
2
|
+
=begin
|
3
|
+
An Optical System is a set of Optical Elements, generally arranged in a line.
|
4
|
+
=end
|
5
|
+
class System
|
6
|
+
# @!attribute elements
|
7
|
+
# @return [Array] the set of elements in the system
|
8
|
+
attr_reader :elements
|
9
|
+
|
10
|
+
# @!attribute spacing
|
11
|
+
# @return [Number] the default spacing to add between newly added elements
|
12
|
+
attr_accessor :spacing
|
13
|
+
|
14
|
+
# Convenience method for creating a new {Spacer}
|
15
|
+
def self.spacer(space)
|
16
|
+
Spacer::new(space)
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@elements = []
|
21
|
+
end
|
22
|
+
|
23
|
+
# Append a new Optical element
|
24
|
+
# @return [System]
|
25
|
+
def push(element)
|
26
|
+
if element.is_a?(Numeric)
|
27
|
+
@elements.push Spacer.new(element)
|
28
|
+
elsif element.is_a?(Spacer)
|
29
|
+
@elements.push element
|
30
|
+
else
|
31
|
+
@elements.push Spacer.new(spacing) if spacing && !(elements.empty? || elements.last.is_a?(Spacer))
|
32
|
+
@elements.push element
|
33
|
+
end
|
34
|
+
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
class Spacer
|
39
|
+
attr_reader :space
|
40
|
+
|
41
|
+
# @param space [Number] the length of the {Spacer}
|
42
|
+
def initialize(space)
|
43
|
+
@space = space
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/optical.gemspec
CHANGED
@@ -4,12 +4,12 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "optical"
|
7
|
-
spec.version = '0'
|
7
|
+
spec.version = '0.1'
|
8
8
|
spec.authors = ["Brandon Fosdick"]
|
9
9
|
spec.email = ["bfoz@bfoz.net"]
|
10
10
|
spec.summary = %q{Optical systems in Ruby}
|
11
11
|
spec.description = %q{The home of all ruby optics}
|
12
|
-
spec.homepage = "http://github.com/
|
12
|
+
spec.homepage = "http://github.com/bfoz/optical-ruby"
|
13
13
|
spec.license = "BSD"
|
14
14
|
|
15
15
|
spec.files = `git ls-files -z`.split("\x0")
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'optical/lens'
|
3
|
+
|
4
|
+
describe Optical::Lens do
|
5
|
+
it 'must initialize itself from named parameters' do
|
6
|
+
lens = Optical::Lens.new(radius:1, focal_length:5)
|
7
|
+
lens.must_be_instance_of Optical::Lens
|
8
|
+
lens.diameter.must_equal 2
|
9
|
+
lens.focal_length.must_equal 5
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'must have a center thickness' do
|
13
|
+
Optical::Lens.new(center_thickness: 5).center_thickness.must_equal 5
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'must have an edge thickness' do
|
17
|
+
Optical::Lens.new(edge_thickness: 4).edge_thickness.must_equal 4
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'must have a thickness attribute that is the maximum thickness' do
|
21
|
+
Optical::Lens.new(center_thickness:2, edge_thickness:5).thickness.must_equal 5
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'must have a numerical aperture' do
|
25
|
+
lens = Optical::Lens.new(radius:1, focal_length:5)
|
26
|
+
lens.numerical_aperture.must_be_close_to 0.196
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'optical/plano_convex_lens'
|
3
|
+
|
4
|
+
describe Optical::PlanoConvexLens do
|
5
|
+
let(:lens) { Optical::PlanoConvexLens.new(center_thickness:3, diameter:15, edge_thickness:2, radius_of_curvature:20) }
|
6
|
+
|
7
|
+
it 'must report the maximum thickness when no arguments are given' do
|
8
|
+
lens.thickness.must_equal 3
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'must report the thickness at a given radius' do
|
12
|
+
lens.thickness(5).must_be_close_to 2.364
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'must report the thickness at a given radius with a named parameter' do
|
16
|
+
lens.thickness(radius:5).must_be_close_to 2.364
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'must report the thickness at a given diameter with a named parameter' do
|
20
|
+
lens.thickness(diameter:10).must_equal lens.thickness(radius:5)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'must raise an exception if the requested radius is outside the lens' do
|
24
|
+
->{ lens.thickness(radius:10) }.must_raise ArgumentError
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'optical/system'
|
3
|
+
|
4
|
+
describe Optical::System do
|
5
|
+
let(:subject) { Optical::System.new }
|
6
|
+
|
7
|
+
it 'must not have any elements' do
|
8
|
+
subject.elements.empty?.must_equal true
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'must push a Lens' do
|
12
|
+
subject.push Optical::Lens.new
|
13
|
+
subject.elements.length.must_equal 1
|
14
|
+
subject.elements.last.must_be_instance_of Optical::Lens
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'must push multiple Lenses' do
|
18
|
+
subject.push Optical::Lens.new
|
19
|
+
subject.push Optical::Lens.new
|
20
|
+
subject.elements.length.must_equal 2
|
21
|
+
subject.elements.all? {|e| e.is_a? Optical::Lens }.must_equal true
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'must push a Lens and a Spacer' do
|
25
|
+
subject.push Optical::Lens.new
|
26
|
+
subject.push Optical::System.spacer(10)
|
27
|
+
subject.elements.length.must_equal 2
|
28
|
+
subject.elements.first.must_be_instance_of Optical::Lens
|
29
|
+
subject.elements.last.must_be_instance_of Optical::System::Spacer
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'must push a Lens and a convenience Spacer' do
|
33
|
+
subject.push Optical::Lens.new
|
34
|
+
subject.push 10
|
35
|
+
subject.elements.length.must_equal 2
|
36
|
+
subject.elements.first.must_be_instance_of Optical::Lens
|
37
|
+
subject.elements.last.must_be_instance_of Optical::System::Spacer
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'must have a default spacing between elements' do
|
41
|
+
subject.spacing = 10
|
42
|
+
subject.push Optical::Lens.new
|
43
|
+
subject.push Optical::Lens.new
|
44
|
+
subject.elements.length.must_equal 3
|
45
|
+
subject.elements.first.must_be_instance_of Optical::Lens
|
46
|
+
subject.elements[1].must_be_instance_of Optical::System::Spacer
|
47
|
+
subject.elements.last.must_be_instance_of Optical::Lens
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'must not push two spacers when a default spacing is set' do
|
51
|
+
subject.spacing = 10
|
52
|
+
subject.push Optical::Lens.new
|
53
|
+
subject.push Optical::System.spacer(10)
|
54
|
+
subject.push Optical::Lens.new
|
55
|
+
subject.elements.length.must_equal 3
|
56
|
+
subject.elements.first.must_be_instance_of Optical::Lens
|
57
|
+
subject.elements[1].must_be_instance_of Optical::System::Spacer
|
58
|
+
subject.elements.last.must_be_instance_of Optical::Lens
|
59
|
+
end
|
60
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: optical
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0'
|
4
|
+
version: '0.1'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brandon Fosdick
|
@@ -50,8 +50,14 @@ files:
|
|
50
50
|
- README.markdown
|
51
51
|
- Rakefile
|
52
52
|
- lib/optical.rb
|
53
|
+
- lib/optical/lens.rb
|
54
|
+
- lib/optical/plano_convex_lens.rb
|
55
|
+
- lib/optical/system.rb
|
53
56
|
- optical.gemspec
|
54
|
-
|
57
|
+
- test/optical/lens.rb
|
58
|
+
- test/optical/plano_convex_lens.rb
|
59
|
+
- test/optical/system.rb
|
60
|
+
homepage: http://github.com/bfoz/optical-ruby
|
55
61
|
licenses:
|
56
62
|
- BSD
|
57
63
|
metadata: {}
|
@@ -75,4 +81,7 @@ rubygems_version: 2.2.2
|
|
75
81
|
signing_key:
|
76
82
|
specification_version: 4
|
77
83
|
summary: Optical systems in Ruby
|
78
|
-
test_files:
|
84
|
+
test_files:
|
85
|
+
- test/optical/lens.rb
|
86
|
+
- test/optical/plano_convex_lens.rb
|
87
|
+
- test/optical/system.rb
|