basis-processing 0.5.8 → 0.5.9
Sign up to get free protection for your applications and to get access to all the features.
- data/README +26 -2
- data/basis.gemspec +1 -1
- data/lib/basis_processing.rb +1 -1
- data/lib/coordinate_system.rb +15 -32
- data/lib/demo.rb +1 -1
- data/lib/hash_vector.rb +8 -1
- data/lib/matrix_extensions.rb +14 -0
- data/lib/screen.rb +7 -6
- data/redeploy.sh +3 -0
- metadata +54 -31
- data/lib/matrix_operations.rb +0 -24
data/README
CHANGED
@@ -1,8 +1,18 @@
|
|
1
|
+
Please send bug reports to (avishek.sen.gupta at gmail.com)
|
2
|
+
|
1
3
|
**NOTE: Starting from version 0.5.1, Basis has been ported to Ruby 1.9.2, because of the kd-tree library dependency. Currently, there are no plans of maintaining Basis compatibility with Ruby 1.8.x.**
|
2
4
|
|
3
5
|
**Basis** provides a set of classes for easily plotting and transforming arbitrary 2D coordinate systems by specifying their basis vectors. Originally developed to work with Ruby-Processing, it now supports any class which supports Processing-like semantics.
|
4
6
|
|
5
|
-
Starting from version 0.5.
|
7
|
+
UPDATE: Starting from version 0.5.9, you can turn grid lines on or off.
|
8
|
+
|
9
|
+
UPDATE: Starting from version 0.5.8, you can customise axis labels, draw arbitrary shapes/text/plot custom graphics at any point in your coordinate system. See below for more details.
|
10
|
+
|
11
|
+
UPDATE: With version 0.5.7, experimental support has been added for drawing objects which aren’t points. Interactions with such objects is currently not supported. Additional support for drawing markers/highlighting in custom bases is now in.
|
12
|
+
|
13
|
+
UPDATE: Starting from version 0.5.1, Basis has been ported to Ruby 1.9.2, because of the kd-tree library dependency. Currently, there are no plans of maintaining Basis compatibility with Ruby 1.8.x. As an aside, I personally recommend using RVM to manage the mess of Ruby/JRuby installations that you’re likely to have on your machine.
|
14
|
+
|
15
|
+
UPDATE: Basis has hit version 0.5.0 with experimental support for mouseover interactivity. More work is incoming, but the demo code below is up-to-date, for now. Starting from version 0.5.0, experimental support has been added for mouseover interactivity without (too much) extra effort on your part. This is still a work in progress, though.
|
6
16
|
|
7
17
|
## Installation
|
8
18
|
|
@@ -247,7 +257,21 @@ The other interesting thing about the above code will become evident if we speci
|
|
247
257
|
|
248
258
|
The box plot in this modified basis acquires the properties of skewness, rotation, etc. of the host coordinate system. This lets you get on with drawing the object without really worrying about the specific properties of the coordinate space you are plotting in.
|
249
259
|
|
250
|
-
|
260
|
+
The other variation you can use is the at() method of a Screen object. at() behaves like plot(), except that it never plots anything by itself, instead deferring full control to the block that you pass to it. Think of it as a simple way of accessing any point in your custom coordinate system, without having to perform any of the messy transformations yourself. So, for example, the following code fragment, puts some text at whichever point on screen corresponds to (some_x, some_y) in your custom basis.
|
261
|
+
|
262
|
+
@screen.at({:x => some_x, :y => some_y}) {|o,m,s| text(o[:y], m[:x] + 5, m[:y] + 14)}
|
263
|
+
|
264
|
+
## Axis drawing options
|
265
|
+
|
266
|
+
Starting from version 0.5.8, you can customise labels, if you pass two blocks to the draw_axes() method, one for the x-axis, the other for the y-axis. For example, in the fragment below, we're not outputting anything for the x-axis labels (returning an empty string), and converting the y-axis value to an integer.
|
267
|
+
|
268
|
+
@screen.draw_axes(10, 10, :x => ->(p){''}, :y => ->(p){p.to_i})
|
269
|
+
|
270
|
+
Grid lines are drawn by default. To turn them off, set the :gridlines key to false in the call to draw_axes(), like so:
|
271
|
+
|
272
|
+
@screen.draw_axes(10, 10, :x => ->(p){''}, :y => ->(p){p.to_i}, :gridlines => false)
|
273
|
+
|
274
|
+
## Convenience method for setting up default CoordinateSystem
|
251
275
|
|
252
276
|
If you're doing a simple plot, with standard basis vectors with no transformations, you can use the convenience method in CoordinateSystem to set up a default system.
|
253
277
|
|
data/basis.gemspec
CHANGED
data/lib/basis_processing.rb
CHANGED
data/lib/coordinate_system.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'ranges'
|
2
2
|
require 'ruby-processing'
|
3
|
-
require 'matrix_operations'
|
4
3
|
require 'hash_vector'
|
4
|
+
require 'matrix_extensions'
|
5
5
|
|
6
6
|
include Math
|
7
7
|
|
@@ -16,8 +16,6 @@ end
|
|
16
16
|
class CoordinateSystem
|
17
17
|
CROSSHAIR_SCALE = 5000
|
18
18
|
UNIT_TRANSFORM = [[1,0],[0,1]]
|
19
|
-
|
20
|
-
include MatrixOperations
|
21
19
|
attr_accessor :x_basis_vector, :y_basis_vector, :basis_matrix
|
22
20
|
|
23
21
|
def self.standard(x_range, y_range, artist)
|
@@ -36,27 +34,21 @@ class CoordinateSystem
|
|
36
34
|
@y_axis = y_axis
|
37
35
|
@x_basis_vector = x_axis.basis_vector
|
38
36
|
@y_basis_vector = y_axis.basis_vector
|
39
|
-
@basis_transform = transform
|
40
|
-
@basis_matrix =
|
37
|
+
@basis_transform = Matrix.rows(transform)
|
38
|
+
@basis_matrix = Matrix.rows(
|
41
39
|
[
|
42
40
|
[@x_basis_vector[:x],@y_basis_vector[:x]],
|
43
41
|
[@x_basis_vector[:y],@y_basis_vector[:y]]
|
44
|
-
]
|
45
|
-
|
46
|
-
d = @basis_matrix[0][0]*@basis_matrix[1][1] - @basis_matrix[0][1]*@basis_matrix[1][0]
|
47
|
-
@inverse_basis =
|
48
|
-
[
|
49
|
-
[@basis_matrix[1][1]/d, -@basis_matrix[0][1]/d],
|
50
|
-
[-@basis_matrix[1][0]/d, @basis_matrix[0][0]/d]
|
51
|
-
]
|
42
|
+
])
|
52
43
|
|
53
|
-
@
|
44
|
+
@inverse_basis = @basis_matrix.inverse
|
45
|
+
@standard_transform = @basis_matrix*@basis_transform*@inverse_basis
|
54
46
|
end
|
55
47
|
|
56
48
|
def tick_vectors
|
57
49
|
{
|
58
|
-
:x_tick_vector =>
|
59
|
-
:y_tick_vector =>
|
50
|
+
:x_tick_vector => (rotation(-90)*@x_basis_vector).as_hash,
|
51
|
+
:y_tick_vector => (rotation(90)*@y_basis_vector).as_hash
|
60
52
|
}
|
61
53
|
end
|
62
54
|
|
@@ -82,29 +74,20 @@ class CoordinateSystem
|
|
82
74
|
|
83
75
|
def rotation(angle)
|
84
76
|
radians = angle * PI/180.0
|
85
|
-
[[cos(radians), -sin(radians)],[sin(radians),cos(radians)]]
|
77
|
+
Matrix.rows([[cos(radians), -sin(radians)],[sin(radians),cos(radians)]])
|
86
78
|
end
|
87
79
|
|
88
80
|
|
89
81
|
def standard_basis(point)
|
90
|
-
basis_matrix
|
91
|
-
|
92
|
-
|
93
|
-
[@x_basis_vector[:y], @y_basis_vector[:y]]
|
94
|
-
]
|
95
|
-
standard_point = MatrixOperations::into2Dx1D(basis_matrix, point)
|
96
|
-
|
97
|
-
MatrixOperations::into2Dx1D(@standard_transform, standard_point)
|
82
|
+
standard_point = @basis_matrix* point
|
83
|
+
r = @standard_transform * standard_point
|
84
|
+
{:x => r[0,0], :y => r[1,0]}
|
98
85
|
end
|
99
86
|
|
100
87
|
def original(onscreen_point)
|
101
|
-
p1 =
|
102
|
-
basis_matrix
|
103
|
-
[
|
104
|
-
[@x_basis_vector[:x], @y_basis_vector[:x]],
|
105
|
-
[@x_basis_vector[:y], @y_basis_vector[:y]]
|
106
|
-
]
|
107
|
-
MatrixOperations::into2Dx1D(MatrixOperations::inverse2D(basis_matrix), p1)
|
88
|
+
p1 = @standard_transform.inverse * onscreen_point
|
89
|
+
o = @basis_matrix.inverse* p1
|
90
|
+
{:x => o[0][0], :y => o[1][0]}
|
108
91
|
end
|
109
92
|
|
110
93
|
def crosshairs(p)
|
data/lib/demo.rb
CHANGED
@@ -39,7 +39,7 @@ class Demo < Processing::App
|
|
39
39
|
|
40
40
|
screen_transform = Transform.new({:x => 2, :y => -2}, {:x => 300, :y => 900})
|
41
41
|
@screen = Screen.new(screen_transform, self, @basis)
|
42
|
-
@screen.draw_axes(10,10)
|
42
|
+
@screen.draw_axes(10,10, :gridlines => false)
|
43
43
|
stroke(1,1,0,1)
|
44
44
|
fill(1,1,0)
|
45
45
|
rect_mode(CENTER)
|
data/lib/hash_vector.rb
CHANGED
@@ -1,9 +1,16 @@
|
|
1
|
+
require 'matrix'
|
2
|
+
|
1
3
|
class Hash
|
2
4
|
def *(scalar)
|
3
5
|
{:x => self[:x] * scalar.to_f, :y => self[:y] * scalar.to_f}
|
4
6
|
end
|
5
7
|
def +(vector)
|
6
|
-
{:x => self[:x] + vector[:x], :y => self[:y] + vector[:y]}
|
8
|
+
return {:x => self[:x] + vector[:x], :y => self[:y] + vector[:y]} if vector.kind_of? Hash
|
9
|
+
{:x => self[:x] + vector[0,0], :y => self[:y] + vector[1,0]}
|
10
|
+
end
|
11
|
+
|
12
|
+
def as_matrix
|
13
|
+
Matrix.columns([[self[:x], self[:y]]])
|
7
14
|
end
|
8
15
|
end
|
9
16
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'matrix'
|
2
|
+
|
3
|
+
class Matrix
|
4
|
+
alias_method :multiply, :*
|
5
|
+
def *(another)
|
6
|
+
return multiply(Matrix.columns([[another[:x], another[:y]]])) if another.kind_of? Hash
|
7
|
+
multiply(another)
|
8
|
+
end
|
9
|
+
|
10
|
+
def as_hash
|
11
|
+
{:x => self[0,0], :y => self[1,0]}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
data/lib/screen.rb
CHANGED
@@ -19,9 +19,9 @@ class Screen
|
|
19
19
|
@points = []
|
20
20
|
@data = []
|
21
21
|
@output = output
|
22
|
-
@transform_matrix = [[@transform.scale[:x], 0],[0, @transform.scale[:y]]]
|
23
|
-
nhm =
|
24
|
-
@affine_transform = PMatrix2D.new(nhm[0
|
22
|
+
@transform_matrix = Matrix.rows([[@transform.scale[:x], 0],[0, @transform.scale[:y]]])
|
23
|
+
nhm = @transform_matrix* @basis.basis_matrix
|
24
|
+
@affine_transform = PMatrix2D.new(nhm[0,0],nhm[0,1],@transform.origin[:x],nhm[1,0],nhm[1,1],@transform.origin[:y])
|
25
25
|
@inverse_affine_transform = @affine_transform.get
|
26
26
|
@inverse_affine_transform.invert
|
27
27
|
end
|
@@ -111,7 +111,7 @@ class Screen
|
|
111
111
|
{:x => 5*vector[:x]/magnitude, :y => 5*vector[:y]/magnitude}
|
112
112
|
end
|
113
113
|
|
114
|
-
def draw_axes(x_interval, y_interval,
|
114
|
+
def draw_axes(x_interval, y_interval, options = {})
|
115
115
|
f = @artist.createFont("Georgia", 24, true);
|
116
116
|
@artist.text_font(f,16)
|
117
117
|
axis_screen_transform = Transform.new({:x => 800, :y => -800}, @transform.origin)
|
@@ -129,10 +129,11 @@ class Screen
|
|
129
129
|
@artist.line(x_ticks.first[:from][:x],x_ticks.first[:from][:y],x_ticks.last[:from][:x],x_ticks.last[:from][:y])
|
130
130
|
@artist.line(y_ticks.first[:from][:x],y_ticks.first[:from][:y],y_ticks.last[:from][:x],y_ticks.last[:from][:y])
|
131
131
|
|
132
|
-
draw_ticks(x_ticks, {:x => 0, :y => 20},
|
133
|
-
draw_ticks(y_ticks, {:x => -50, :y => 0},
|
132
|
+
draw_ticks(x_ticks, {:x => 0, :y => 20}, options[:x])
|
133
|
+
draw_ticks(y_ticks, {:x => -50, :y => 0}, options[:y])
|
134
134
|
|
135
135
|
@artist.stroke(0.4, 1.0, 0.5, 0.2)
|
136
|
+
return if !options[:gridlines].nil? && options[:gridlines] == false
|
136
137
|
grid_lines = @basis.grid_lines(x_interval, y_interval).collect {|gl| {:from => @transform.apply(gl[:from]), :to => @transform.apply(gl[:to])}}
|
137
138
|
grid_lines.each do |l|
|
138
139
|
@artist.line(l[:from][:x],l[:from][:y],l[:to][:x],l[:to][:y])
|
data/redeploy.sh
ADDED
metadata
CHANGED
@@ -1,34 +1,47 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: basis-processing
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 5
|
9
|
+
- 9
|
10
|
+
version: 0.5.9
|
6
11
|
platform: ruby
|
7
|
-
authors:
|
12
|
+
authors:
|
8
13
|
- Avishek Sen Gupta
|
9
14
|
autorequire:
|
10
15
|
bindir: bin
|
11
16
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
17
|
+
|
18
|
+
date: 2011-10-25 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
15
21
|
name: knnball
|
16
|
-
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
17
24
|
none: false
|
18
|
-
requirements:
|
19
|
-
- -
|
20
|
-
- !ruby/object:Gem::Version
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 19
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
- 0
|
32
|
+
- 6
|
21
33
|
version: 0.0.6
|
22
34
|
type: :runtime
|
23
|
-
|
24
|
-
|
25
|
-
description: Basis provides a set of classes for easily plotting and transforming
|
26
|
-
arbitrary 2D coordinate systems by specifying their basis vectors in Ruby-Processing.
|
35
|
+
version_requirements: *id001
|
36
|
+
description: Basis provides a set of classes for easily plotting and transforming arbitrary 2D coordinate systems by specifying their basis vectors in Ruby-Processing.
|
27
37
|
email: avishek.sen.gupta@gmail.com
|
28
38
|
executables: []
|
39
|
+
|
29
40
|
extensions: []
|
41
|
+
|
30
42
|
extra_rdoc_files: []
|
31
|
-
|
43
|
+
|
44
|
+
files:
|
32
45
|
- .gitignore
|
33
46
|
- README
|
34
47
|
- basis.gemspec
|
@@ -40,34 +53,44 @@ files:
|
|
40
53
|
- lib/demo.rb
|
41
54
|
- lib/hash_vector.rb
|
42
55
|
- lib/interactive.rb
|
43
|
-
- lib/
|
56
|
+
- lib/matrix_extensions.rb
|
44
57
|
- lib/ranges.rb
|
45
58
|
- lib/screen.rb
|
46
59
|
- lib/text_output.rb
|
47
60
|
- lib/transform.rb
|
61
|
+
- redeploy.sh
|
48
62
|
homepage: http://avishek.net/blog
|
49
63
|
licenses: []
|
64
|
+
|
50
65
|
post_install_message:
|
51
66
|
rdoc_options: []
|
52
|
-
|
67
|
+
|
68
|
+
require_paths:
|
53
69
|
- lib
|
54
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
71
|
none: false
|
56
|
-
requirements:
|
57
|
-
- -
|
58
|
-
- !ruby/object:Gem::Version
|
59
|
-
|
60
|
-
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
hash: 3
|
76
|
+
segments:
|
77
|
+
- 0
|
78
|
+
version: "0"
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
80
|
none: false
|
62
|
-
requirements:
|
63
|
-
- -
|
64
|
-
- !ruby/object:Gem::Version
|
65
|
-
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
hash: 3
|
85
|
+
segments:
|
86
|
+
- 0
|
87
|
+
version: "0"
|
66
88
|
requirements: []
|
89
|
+
|
67
90
|
rubyforge_project:
|
68
|
-
rubygems_version: 1.
|
91
|
+
rubygems_version: 1.7.2
|
69
92
|
signing_key:
|
70
93
|
specification_version: 3
|
71
|
-
summary: Basis provides a set of classes for easily plotting and transforming arbitrary
|
72
|
-
2D coordinate systems by specifying their basis vectors in Ruby-Processing.
|
94
|
+
summary: Basis provides a set of classes for easily plotting and transforming arbitrary 2D coordinate systems by specifying their basis vectors in Ruby-Processing.
|
73
95
|
test_files: []
|
96
|
+
|
data/lib/matrix_operations.rb
DELETED
@@ -1,24 +0,0 @@
|
|
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
|
-
|
16
|
-
def MatrixOperations.inverse2D(m)
|
17
|
-
determinant = (m[0][0]*m[1][1] - m[0][1]*m[1][0]).to_f;
|
18
|
-
[
|
19
|
-
[m[1][1]/determinant, -m[0][1]/determinant],
|
20
|
-
[-m[1][0]/determinant, m[0][0]/determinant]
|
21
|
-
]
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|