optical 0 → 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|