basis-processing 0.4 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/basis.gemspec +1 -1
- data/lib/basis_processing.rb +4 -0
- data/lib/coordinate_system.rb +99 -0
- data/lib/demo.rb +42 -0
- data/lib/matrix_operations.rb +16 -0
- data/lib/ranges.rb +48 -0
- data/lib/screen.rb +41 -0
- data/lib/transform.rb +18 -0
- metadata +10 -2
data/basis.gemspec
CHANGED
@@ -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
|
+
|
data/lib/demo.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'ranges'
|
2
|
+
require 'transform'
|
3
|
+
require 'coordinate_system'
|
4
|
+
require 'screen'
|
5
|
+
|
6
|
+
class Demo < Processing::App
|
7
|
+
app = self
|
8
|
+
def setup
|
9
|
+
smooth
|
10
|
+
background(0,0,0)
|
11
|
+
color_mode(RGB, 1.0)
|
12
|
+
stroke(1,1,0,1)
|
13
|
+
|
14
|
+
points = []
|
15
|
+
100.times {points << {:x => random(200), :y => random(300)}}
|
16
|
+
|
17
|
+
x_basis_vector = {:x => 1.0, :y => 0.0}
|
18
|
+
y_basis_vector = {:x => 0.0, :y => 1.0}
|
19
|
+
|
20
|
+
x_range = ContinuousRange.new({:minimum => 0, :maximum => 200})
|
21
|
+
y_range = ContinuousRange.new({:minimum => 0, :maximum => 300})
|
22
|
+
|
23
|
+
basis = CoordinateSystem.new(Axis.new(x_basis_vector,x_range), Axis.new(y_basis_vector,y_range), [[4,0],[0,2]], self)
|
24
|
+
screen_transform = SignedTransform.new({:x => 10, :y => -1}, {:x => 300, :y => 900})
|
25
|
+
screen = Screen.new(screen_transform, self)
|
26
|
+
screen.draw_axes(basis,10,10)
|
27
|
+
stroke(1,1,0,1)
|
28
|
+
fill(1,1,0)
|
29
|
+
points.each do |p|
|
30
|
+
screen.plot(p, basis)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def draw
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
w = 1200
|
39
|
+
h = 1000
|
40
|
+
|
41
|
+
Demo.new(:title => "My Sketch", :width => w, :height => h)
|
42
|
+
|
@@ -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/lib/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/lib/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/lib/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
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: basis-processing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 13
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 4
|
9
|
-
|
9
|
+
- 1
|
10
|
+
version: 0.4.1
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Avishek Sen Gupta
|
@@ -29,6 +30,13 @@ files:
|
|
29
30
|
- .gitignore
|
30
31
|
- README
|
31
32
|
- basis.gemspec
|
33
|
+
- lib/basis_processing.rb
|
34
|
+
- lib/coordinate_system.rb
|
35
|
+
- lib/demo.rb
|
36
|
+
- lib/matrix_operations.rb
|
37
|
+
- lib/ranges.rb
|
38
|
+
- lib/screen.rb
|
39
|
+
- lib/transform.rb
|
32
40
|
homepage: http://avishek.net/blog
|
33
41
|
licenses: []
|
34
42
|
|