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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: eb544a2d0d771d7f974dfdee13db65f1c319f491
4
- data.tar.gz: 4b82e4f906e8df0ced3a0256d4018c5a3d240f8f
3
+ metadata.gz: 4f4400f4aa624b50b95186d0ead6ddb5a1c033f9
4
+ data.tar.gz: b0bed9445d1164a994190e77dcb6192ebd19f119
5
5
  SHA512:
6
- metadata.gz: 734e368031fd49482e0f777794c7acd9d612703ee96d5fcad9ccd71887f9526bf65f64c8fe6c6da9f9d1b44ae54c29d8884e90cbffbd197407ebdae96220c7c6
7
- data.tar.gz: 666d841c393776ca915a65d531f6ea9c402c9239bb64c58293cc1971d2488f9148406791cea694ee3b90d7055fa58ec8c4750eaf92647a4b4f95f0c124e48442
6
+ metadata.gz: 0014fcd6738e371bb5c03c2d4ccda9dbe22f592faa1513f1696e0749a750920f846b53c6f1a8628dd2be259e04473e5218d32b30aa1443ef8e084564b017086b
7
+ data.tar.gz: d0ebe9fe8cc259406cf326f617b856d49775fd8fcfd441ca866b6592cd8d96c82dec100105126a53a94f9f6cc3d3d9a77cc53383b214e1221cc55453a2aefae2
@@ -1,6 +1,6 @@
1
1
  # Optical
2
2
 
3
- TODO: Write a gem description
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
- TODO: Write usage instructions here
21
+ ### Lenses
22
22
 
23
- ## Contributing
23
+ The optical gem has primitives for modeling generic thin-lenses, as well as more specific lens types.
24
24
 
25
- 1. Fork it ( https://github.com/[my-github-username]/optical/fork )
26
- 2. Create your feature branch (`git checkout -b my-new-feature`)
27
- 3. Commit your changes (`git commit -am 'Add some feature'`)
28
- 4. Push to the branch (`git push origin my-new-feature`)
29
- 5. Create a new Pull Request
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
@@ -1,2 +1,10 @@
1
1
  require "bundler/gem_tasks"
2
+ require 'rake/testtask'
2
3
 
4
+ task :default => :test
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.libs.push 'lib'
8
+ t.test_files = FileList['test/**/*.rb']
9
+ t.verbose = true
10
+ end
@@ -1,3 +1,6 @@
1
+ require 'optical/lens'
2
+ require 'optical/plano_convex_lens'
3
+ require 'optical/system'
4
+
1
5
  module Optical
2
- # Your code goes here...
3
6
  end
@@ -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
@@ -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/TemplateLabs/optical-ruby"
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
- homepage: http://github.com/TemplateLabs/optical-ruby
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