basis-processing 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,99 @@
1
+ require 'ranges'
2
+ require 'ruby-processing'
3
+ require 'matrix_operations'
4
+
5
+ include Math
6
+
7
+ class Axis
8
+ attr_accessor :basis_vector, :range
9
+ def initialize(basis_vector, range)
10
+ @basis_vector = basis_vector
11
+ @range = range
12
+ end
13
+ end
14
+
15
+ class CoordinateSystem
16
+ include MatrixOperations
17
+ attr_accessor :x_basis_vector, :y_basis_vector
18
+
19
+ def initialize(x_axis, y_axis, transform, artist)
20
+ @artist = artist
21
+ @x_axis = x_axis
22
+ @y_axis = y_axis
23
+ @x_basis_vector = x_axis.basis_vector
24
+ @y_basis_vector = y_axis.basis_vector
25
+ @basis_transform = transform
26
+ @basis_matrix =
27
+ [
28
+ [@x_basis_vector[:x],@y_basis_vector[:x]],
29
+ [@x_basis_vector[:y],@y_basis_vector[:y]]
30
+ ]
31
+
32
+ d = @basis_matrix[0][0]*@basis_matrix[1][1] - @basis_matrix[0][1]*@basis_matrix[1][0]
33
+ @inverse_basis =
34
+ [
35
+ [@basis_matrix[1][1]/d, -@basis_matrix[0][1]/d],
36
+ [-@basis_matrix[1][0]/d, @basis_matrix[0][0]/d]
37
+ ]
38
+
39
+ @standard_transform = MatrixOperations::into2Dx2D(MatrixOperations::into2Dx2D(@basis_matrix, @basis_transform), @inverse_basis)
40
+ end
41
+
42
+ def tick_vectors
43
+ unnormalised_vectors =
44
+ {
45
+ :x_tick_vector => MatrixOperations::into2Dx1D(rotation(-90),@x_basis_vector),
46
+ :y_tick_vector => MatrixOperations::into2Dx1D(rotation(90),@y_basis_vector)
47
+ }
48
+ {
49
+ :x_tick_vector => normal(unnormalised_vectors[:x_tick_vector]),
50
+ :y_tick_vector => normal(unnormalised_vectors[:y_tick_vector])
51
+ }
52
+ end
53
+
54
+ def normal(vector)
55
+ magnitude = sqrt(vector[:x]**2 + vector[:y]**2)
56
+ {:x => 5*vector[:x]/magnitude, :y => 5*vector[:y]/magnitude}
57
+ end
58
+
59
+ def sum(v1, v2)
60
+ {:x => v1[:x] + v2[:x], :y => v1[:y] + v2[:y]}
61
+ end
62
+
63
+ def x_ticks(x_basis_interval)
64
+ lines = []
65
+ t_vectors = tick_vectors
66
+ @x_axis.range.run(x_basis_interval) do |i,v|
67
+ tick_origin = standard_basis({:x => i, :y => 0})
68
+ lines << {:label => v, :from => tick_origin, :to => sum(tick_origin, t_vectors[:x_tick_vector])}
69
+ end
70
+ lines
71
+ end
72
+
73
+ def y_ticks(y_basis_interval)
74
+ lines = []
75
+ t_vectors = tick_vectors
76
+ @y_axis.range.run(y_basis_interval) do |i,v|
77
+ tick_origin = standard_basis({:x => 0, :y => i})
78
+ lines << {:label => v, :from => tick_origin, :to => sum(tick_origin, t_vectors[:y_tick_vector])}
79
+ end
80
+ lines
81
+ end
82
+
83
+ def rotation(angle)
84
+ radians = angle * PI/180.0
85
+ [[cos(radians), -sin(radians)],[sin(radians),cos(radians)]]
86
+ end
87
+
88
+
89
+ def standard_basis(point)
90
+ standard_point =
91
+ {
92
+ :x => @x_basis_vector[:x]*point[:x] + @y_basis_vector[:x]*point[:y],
93
+ :y => @x_basis_vector[:y]*point[:x] + @y_basis_vector[:y]*point[:y]
94
+ }
95
+
96
+ MatrixOperations::into2Dx1D(@standard_transform, standard_point)
97
+ end
98
+ end
99
+
@@ -0,0 +1,16 @@
1
+ module MatrixOperations
2
+ def MatrixOperations.into2Dx2D(first, second)
3
+ [
4
+ [second[0][0]*first[0][0] + second[1][0]*first[0][1], second[0][1]*first[0][0] + second[1][1]*first[0][1]],
5
+ [second[0][0]*first[1][0] + second[1][0]*first[1][1], second[0][1]*first[1][0] + second[1][1]*first[1][1]]
6
+ ]
7
+ end
8
+
9
+ def MatrixOperations.into2Dx1D(transform, point)
10
+ {
11
+ :x => transform[0][0]*point[:x] + transform[0][1]*point[:y],
12
+ :y => transform[1][0]*point[:x] + transform[1][1]*point[:y]
13
+ }
14
+ end
15
+ end
16
+
data/ranges.rb ADDED
@@ -0,0 +1,48 @@
1
+ class ContinuousRange
2
+ attr_accessor :minimum, :maximum
3
+
4
+ def initialize(range)
5
+ @minimum = range[:minimum]
6
+ @maximum = range[:maximum]
7
+ end
8
+
9
+ def interval
10
+ @maximum - @minimum
11
+ end
12
+
13
+ def index(element)
14
+ element.to_f
15
+ end
16
+
17
+ def run(interval)
18
+ current = @minimum
19
+ while(current <= @maximum)
20
+ yield(current,current)
21
+ current += interval
22
+ end
23
+ end
24
+ end
25
+
26
+ class DiscreteRange
27
+ attr_accessor :values
28
+ def initialize(v)
29
+ @values = v[:values]
30
+ end
31
+
32
+ def interval
33
+ @values.count
34
+ end
35
+
36
+ def index(element)
37
+ @values.index(element)
38
+ end
39
+
40
+ def run(interval)
41
+ current = 0
42
+ while(current <= @values.count - 1)
43
+ yield(current,@values[current])
44
+ current += interval
45
+ end
46
+ end
47
+ end
48
+
data/screen.rb ADDED
@@ -0,0 +1,41 @@
1
+ require 'transform'
2
+
3
+ class Screen
4
+ def initialize(transform, artist)
5
+ @transform = transform
6
+ @artist = artist
7
+ end
8
+
9
+ def plot(point, basis)
10
+ standard_point = basis.standard_basis(point)
11
+ p = @transform.apply(standard_point)
12
+ @artist.ellipse(p[:x], p[:y], 5, 5)
13
+ end
14
+
15
+ def draw_ticks(ticks, displacement)
16
+ ticks.each do |l|
17
+ from = @transform.apply(l[:from])
18
+ to = @transform.apply(l[:to])
19
+ @artist.line(from[:x],from[:y],to[:x],to[:y])
20
+ @artist.fill(1)
21
+ @artist.text(l[:label], to[:x]+displacement[:x], to[:y]+displacement[:y])
22
+ end
23
+ end
24
+
25
+ def draw_axes(basis, x_interval, y_interval)
26
+ f = @artist.createFont("Georgia", 24, true);
27
+ @artist.text_font(f,16)
28
+ @artist.stroke(1,1,1,1)
29
+ axis_screen_transform = Transform.new({:x => 800, :y => -800}, @transform.origin)
30
+ origin = {:x => 0, :y => 0}
31
+ screen_origin = @transform.apply(origin)
32
+ x_basis_edge = axis_screen_transform.apply(basis.x_basis_vector)
33
+ y_basis_edge = axis_screen_transform.apply(basis.y_basis_vector)
34
+ @artist.line(screen_origin[:x],screen_origin[:y],x_basis_edge[:x],x_basis_edge[:y])
35
+ @artist.line(screen_origin[:x],screen_origin[:y],y_basis_edge[:x],y_basis_edge[:y])
36
+
37
+ draw_ticks(basis.x_ticks(x_interval), {:x => 0, :y => 20})
38
+ draw_ticks(basis.y_ticks(y_interval), {:x => -50, :y => 0})
39
+ end
40
+ end
41
+
data/transform.rb ADDED
@@ -0,0 +1,18 @@
1
+ class Transform
2
+ attr_accessor :scale, :origin
3
+ def initialize(scale, origin)
4
+ @origin = origin
5
+ @scale = scale
6
+ end
7
+
8
+ def apply(p)
9
+ { :x => @origin[:x] + p[:x] * @scale[:x], :y => @origin[:y] + p[:y] * @scale[:y]}
10
+ end
11
+ end
12
+
13
+ class SignedTransform < Transform
14
+ def apply(p)
15
+ { :x => @origin[:x] + p[:x] * (@scale[:x]<=>0.0).to_i, :y => @origin[:y] + p[:y] * (@scale[:y]<=>0.0).to_i}
16
+ end
17
+ end
18
+
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: basis-processing
3
+ version: !ruby/object:Gem::Version
4
+ hash: 9
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ version: "0.1"
10
+ platform: ruby
11
+ authors:
12
+ - Avishek Sen Gupta
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-08-20 00:00:00 Z
18
+ dependencies: []
19
+
20
+ description: Basis provides a set of classes for easily plotting and transforming arbitrary 2D coordinate systems by specifying their basis vectors in Ruby-Processing.
21
+ email: avishek.sen.gupta@gmail.com
22
+ executables: []
23
+
24
+ extensions: []
25
+
26
+ extra_rdoc_files: []
27
+
28
+ files:
29
+ - transform.rb
30
+ - ranges.rb
31
+ - coordinate_system.rb
32
+ - matrix_operations.rb
33
+ - screen.rb
34
+ homepage: http://avishek.net/blog
35
+ licenses: []
36
+
37
+ post_install_message:
38
+ rdoc_options: []
39
+
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ hash: 3
48
+ segments:
49
+ - 0
50
+ version: "0"
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ requirements: []
61
+
62
+ rubyforge_project:
63
+ rubygems_version: 1.7.2
64
+ signing_key:
65
+ specification_version: 3
66
+ summary: Basis provides a set of classes for easily plotting and transforming arbitrary 2D coordinate systems by specifying their basis vectors in Ruby-Processing.
67
+ test_files: []
68
+