basis-processing 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/coordinate_system.rb +99 -0
- data/matrix_operations.rb +16 -0
- data/ranges.rb +48 -0
- data/screen.rb +41 -0
- data/transform.rb +18 -0
- metadata +68 -0
@@ -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
|
+
|