flame_channel_parser 1.1.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.
@@ -0,0 +1,73 @@
1
+ require "test/unit"
2
+
3
+ class TestFlameChannelParser < Test::Unit::TestCase
4
+ D = 0.0001
5
+
6
+ def test_parsing_baked_timewarp_from_2011
7
+ data = File.open(File.dirname(__FILE__) + "/snaps/TW.timewarp")
8
+ chan = FlameChannelParser.parse(data).find{|c| c.name == "Timing/Timing"}
9
+ assert_equal 816, chan.length
10
+ assert_equal 1, chan[0].frame
11
+ assert_equal 816, chan[-1].frame
12
+ end
13
+
14
+ def test_parsing
15
+ data = File.open(File.dirname(__FILE__) + "/sample_channel.dat")
16
+ channels = FlameChannelParser.parse(data)
17
+ assert_kind_of Array, channels
18
+ assert_equal 1, channels.length, "Should find one channel"
19
+
20
+ assert_kind_of FlameChannelParser::Parser2011::ChannelBlock, channels[0]
21
+
22
+ ch = channels[0]
23
+ assert_equal 4, ch.length
24
+
25
+ peculiar_key = ch[1]
26
+ assert_in_delta D, 858.177, peculiar_key.value
27
+ assert_in_delta D, 2.31503, peculiar_key.left_slope
28
+ assert_in_delta D, 2.31503, peculiar_key.right_slope
29
+ assert_equal :constant, peculiar_key.interpolation
30
+ end
31
+
32
+ def test_action
33
+ f = File.open(File.dirname(__FILE__) + "/snaps/FLEM_curves_example.action")
34
+ channels = FlameChannelParser.parse(f)
35
+
36
+ assert_kind_of Array, channels
37
+ assert_equal 65, channels.length, "Should find 65 channels"
38
+ channels.reject!{|c| c.length < 2 }
39
+ assert_equal 2, channels.length, "Should have 2 channels with more than 2 keyframes"
40
+ last_chan = channels[-1]
41
+ assert_equal "position/y", last_chan.name
42
+ assert_equal 6, last_chan.length
43
+ end
44
+
45
+ def test_action_from_2012
46
+ f = File.open(File.dirname(__FILE__) + "/snaps/FLEM_advanced_curve_example_FL2012.action")
47
+ channels = FlameChannelParser.parse(f)
48
+
49
+ assert_kind_of Array, channels
50
+ assert_equal 65, channels.length, "Should find 65 channels"
51
+ channels.reject!{|c| c.length < 2 }
52
+ assert_equal 2, channels.length, "Should have 2 channels with more than 2 keyframes"
53
+
54
+ last_chan = channels[-1]
55
+ assert_equal "position/y", last_chan.name
56
+ assert_equal 9, last_chan.length
57
+ end
58
+
59
+ def test_action_migrated_to_2012
60
+ f = File.open(File.dirname(__FILE__) + "/snaps/FLEM_curves_example_migrated_to_2012.action")
61
+ channels = FlameChannelParser.parse(f)
62
+
63
+ assert_kind_of Array, channels
64
+ assert_equal 65, channels.length, "Should find 65 channels"
65
+ channels.reject!{|c| c.length < 2 }
66
+ assert_equal 2, channels.length, "Should have 2 channels with more than 2 keyframes"
67
+
68
+ last_chan = channels[-1]
69
+ assert_equal "position/y", last_chan.name
70
+ assert_equal 6, last_chan.length
71
+ end
72
+
73
+ end
@@ -0,0 +1,89 @@
1
+ require "test/unit"
2
+ require "stringio"
3
+
4
+ require File.dirname(__FILE__) + "/../lib/flame_channel_parser"
5
+
6
+ class TestInterpolator < Test::Unit::TestCase
7
+ DELTA = 0.05
8
+
9
+ def assert_same_interpolation(range, ref_channel, sample_channel)
10
+ ref_i, sample_i = [ref_channel, sample_channel].map{|c| FlameChannelParser::Interpolator.new(c) }
11
+
12
+ value_tuples = range.map do |f|
13
+ [f, ref_i.sample_at(f), sample_i.sample_at(f)]
14
+ end
15
+
16
+ begin
17
+ value_tuples.each do | frame, ref, actual |
18
+ assert_in_delta ref, actual, DELTA, "At #{frame} interpolated value should be in delta"
19
+ end
20
+ rescue Test::Unit::AssertionFailedError => e
21
+ STDERR.puts "Curves were not the same so I will now copy the two curves to the clipboard"
22
+ # This is handy for plotting
23
+ IO.popen("pbcopy", "w") do | buf |
24
+ range.map{|f| buf.puts "%03f\t%03f" % [ref_i.sample_at(f), sample_i.sample_at(f)] }
25
+ end
26
+ raise e
27
+ end
28
+ end
29
+
30
+ def test_channel_with_constants
31
+ data = File.open(File.dirname(__FILE__) + "/channel_with_constants.dat")
32
+ constants = FlameChannelParser.parse(data).find{|c| c.name == "constants"}
33
+ interp = FlameChannelParser::Interpolator.new(constants)
34
+
35
+ vs = [770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 770.41, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 858.177, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 939.407, 1017.36, 1017.36]
36
+
37
+ values = (-5..116).map{|f| interp.sample_at(f) }
38
+ assert_equal vs, values
39
+ end
40
+
41
+ def test_baked_timewarp_from_2011
42
+ data = File.open(File.dirname(__FILE__) + "/snaps/TW.timewarp")
43
+ chan = FlameChannelParser.parse(data).find{|c| c.name == "Timing/Timing"}
44
+ sampler = FlameChannelParser::Interpolator.new(chan)
45
+
46
+ assert_equal 1, sampler.first_defined_frame
47
+ assert_equal 816, sampler.last_defined_frame
48
+ end
49
+
50
+ def test_simple_setup_from_2011
51
+ data = File.open(File.dirname(__FILE__) + "/snaps/FLEM_curves_example.action")
52
+ channels_in_action = FlameChannelParser::Parser2011.new.parse(data)
53
+ channels_in_action.reject!{|c| c.length < 4 }
54
+
55
+ reference = channels_in_action.find{|c| c.name == "position/x" && c.length > 2}
56
+ sampled = channels_in_action.find{|c| c.name == "position/y" && c.length > 2}
57
+ assert_same_interpolation(1..200, reference, sampled)
58
+ end
59
+
60
+ def test_broken_tangents_setup_from_2011
61
+ data = File.open(File.dirname(__FILE__) + "/snaps/FLEM_BrokenTangents.action")
62
+ channels_in_action = FlameChannelParser.parse(data)
63
+ channels_in_action.reject!{|c| c.length < 4 }
64
+
65
+ reference = channels_in_action.find{|c| c.name == "position/x" }
66
+ sampled = channels_in_action.find{|c| c.name == "position/y" }
67
+ assert_same_interpolation(1..200, reference, sampled)
68
+ end
69
+
70
+ def test_setup_moved_from_2011_to_2012_parses_the_same
71
+ data = File.open(File.dirname(__FILE__) + "/snaps/FLEM_curves_example.action")
72
+ data_2012 = File.open(File.dirname(__FILE__) + "/snaps/FLEM_curves_example_migrated_to_2012.action")
73
+
74
+ ref = FlameChannelParser.parse(data).find{|e| e.name == "position/x" && e.length > 12 }
75
+ sampled = FlameChannelParser.parse(data_2012).find{|e| e.name == "position/y" && e.length > 5 }
76
+
77
+ assert_same_interpolation(1..200, ref, sampled)
78
+ end
79
+
80
+ def test_setup_from_2012_with_beziers
81
+ data = File.open(File.dirname(__FILE__) + "/snaps/FLEM_advanced_curve_example_FL2012.action")
82
+ channels_in_action = FlameChannelParser.parse(data)
83
+ channels_in_action.reject!{|c| c.length < 4 }
84
+
85
+ reference = channels_in_action.find{|c| c.name == "position/x" && c.length > 2 }
86
+ sampled = channels_in_action.find{|c| c.name == "position/y" && c.length > 2 }
87
+ assert_same_interpolation(1..330, reference, sampled)
88
+ end
89
+ end
@@ -0,0 +1,261 @@
1
+ require "test/unit"
2
+ require File.dirname(__FILE__) + "/../lib/flame_channel_parser"
3
+
4
+ D = 0.001
5
+
6
+ include FlameChannelParser::Segments
7
+
8
+ class TestConstantFunction < Test::Unit::TestCase
9
+ def test_segment
10
+ seg = ConstantFunction.new(123.4)
11
+ assert seg.defines?(-1), "The segment should define this frame"
12
+ assert seg.defines?(4567), "The segment should define this frame"
13
+ assert_equal 123.4, seg.value_at(123), "This is the segment's constant value"
14
+ end
15
+ end
16
+
17
+
18
+ class TestConstantSegment < Test::Unit::TestCase
19
+ def test_segment
20
+ seg = ConstantSegment.new(12, 25, 2.5)
21
+
22
+ assert !seg.defines?(11), "This frame is outside the segment"
23
+ assert !seg.defines?(26), "This frame is outside the segment"
24
+ assert seg.defines?(12), "Frame 12 defined"
25
+ assert seg.defines?(24), "Frame 24 defined"
26
+
27
+ assert_equal 2.5, seg.value_at(11)
28
+ assert_equal 2.5, seg.value_at(14)
29
+ assert_equal 2.5, seg.value_at(26)
30
+ end
31
+ end
32
+
33
+ class TestBezierSegment < Test::Unit::TestCase
34
+ D = 0.001
35
+
36
+ def test_segment
37
+ seg = BezierSegment.new(
38
+ frame_from = 117,
39
+ frame_to = 149,
40
+ value_from = 1.23907006,
41
+ value_to = 258.239014,
42
+ handle_left_x = 117.25,
43
+ handle_left_y = 4.76008224,
44
+ handle_right_x = 138.333328,
45
+ handle_right_y = 258.398254
46
+ )
47
+ assert seg.defines?(117)
48
+ assert !seg.defines?(149)
49
+ assert !seg.defines?(151)
50
+ assert !seg.defines?(116)
51
+
52
+ assert_in_delta 1.23907006, seg.value_at(25), D
53
+ assert_in_delta 24.7679917574603, seg.value_at(119), D
54
+ end
55
+ end
56
+
57
+ class TestLinearSegment < Test::Unit::TestCase
58
+ def test_segment
59
+ seg = LinearSegment.new(12, 25, 2.5, 4.5)
60
+
61
+ assert !seg.defines?(11), "This frame is outside the segment"
62
+ assert !seg.defines?(26), "This frame is outside the segment"
63
+ assert seg.defines?(12), "Frame 12 defined"
64
+ assert seg.defines?(24), "Frame 24 defined"
65
+
66
+ assert_in_delta 2.8076, seg.value_at(14), D
67
+ assert_in_delta 2.9615, seg.value_at(15), D
68
+ end
69
+ end
70
+
71
+
72
+ class TestConstantPrepolate < Test::Unit::TestCase
73
+ def test_segment
74
+ seg = ConstantPrepolate.new(12, 234.5)
75
+ assert seg.defines?(11)
76
+ assert !seg.defines?(12)
77
+ assert !seg.defines?(13)
78
+ assert seg.defines?(-1234)
79
+ assert_equal 234.5, seg.value_at(12)
80
+ end
81
+ end
82
+
83
+ class TestHermiteSegment < Test::Unit::TestCase
84
+ def test_last_curve_segment
85
+ refdata = %w(
86
+ 258.239
87
+ 257.937
88
+ 257.074
89
+ 255.674
90
+ 253.759
91
+ 251.352
92
+ 248.476
93
+ 245.152
94
+ 241.405
95
+ 237.255
96
+ 232.727
97
+ 227.842
98
+ 222.624
99
+ 217.094
100
+ 211.276
101
+ 205.192
102
+ 198.865
103
+ 192.317
104
+ 185.571
105
+ 178.65
106
+ 171.576
107
+ 164.372
108
+ 157.06
109
+ 149.664
110
+ 142.205
111
+ 134.707
112
+ 127.192
113
+ 119.683
114
+ 112.202
115
+ 104.772
116
+ 97.4151
117
+ 90.1547
118
+ 83.0132
119
+ 76.0132
120
+ 69.1772
121
+ 62.528
122
+ 56.0881
123
+ 49.8802
124
+ 43.9269
125
+ 38.2508
126
+ 32.8746
127
+ 27.8209
128
+ 23.1124
129
+ 18.7715
130
+ 14.8212
131
+ 11.2838
132
+ 8.18198
133
+ 5.53853
134
+ 3.37598
135
+ 1.71692
136
+ 0.584045
137
+ 0.0
138
+ ).map{|e| e.to_f }
139
+
140
+ herm = HermiteSegment.new(
141
+ time_from = 149,
142
+ time_to = 200,
143
+ value1 = 258.239,
144
+ value2 = 0,
145
+ tangent1 = -0.0149286,
146
+ tangent2 = -0.302127
147
+ )
148
+
149
+ interpolated = (149..200).map(&herm.method(:value_at))
150
+
151
+ refdata.zip(interpolated).each do | ref, actual |
152
+ assert_in_delta ref, actual, D, "Interpolated value should be in delta"
153
+ end
154
+ end
155
+
156
+ def test_first_curve_segment
157
+ refdata = %w(
158
+ 222.919
159
+ 222.543
160
+ 221.735
161
+ 220.506
162
+ 218.867
163
+ 216.83
164
+ 214.406
165
+ 211.608
166
+ 208.445
167
+ 204.931
168
+ 201.075
169
+ 196.89
170
+ 192.387
171
+ 187.578
172
+ 182.473
173
+ 177.085
174
+ 171.425
175
+ 165.503
176
+ 159.333
177
+ 152.924
178
+ 146.29
179
+ 139.44
180
+ 132.386
181
+ 125.141
182
+ 117.715
183
+ 110.119
184
+ 102.366
185
+ 94.4661
186
+ 86.4316
187
+ 78.2735
188
+ 70.0034
189
+ 61.6327
190
+ 53.1728
191
+ 44.6353
192
+ 36.0314
193
+ 27.3727
194
+ 18.6705
195
+ 9.93645
196
+ 1.18185
197
+ -7.58185
198
+ -16.3432
199
+ -25.0907
200
+ -33.813
201
+ -42.4985
202
+ -51.136
203
+ -59.714
204
+ -68.2209
205
+ -76.6454
206
+ -84.9759
207
+ -93.2012
208
+ -101.31
209
+ -109.29
210
+ -117.131
211
+ -124.82
212
+ -132.347
213
+ -139.7
214
+ -146.868
215
+ -153.839
216
+ -160.601
217
+ -167.144
218
+ -173.456
219
+ -179.525
220
+ -185.34
221
+ -190.889
222
+ -196.162
223
+ -201.146
224
+ -205.83
225
+ -210.204
226
+ -214.254
227
+ -217.97
228
+ -221.341
229
+ -224.355
230
+ -227.0
231
+ ).map{|e| e.to_f }
232
+
233
+ herm = HermiteSegment.new(
234
+ time_from = 22,
235
+ time_to = 94,
236
+ value1 = 222.919,
237
+ value2 = -227.0,
238
+ tangent1 = -0.156017,
239
+ tangent2 = -2.45723
240
+ )
241
+
242
+ interpolated = (22..94).map(&herm.method(:value_at))
243
+
244
+ (22..94).to_a.zip(refdata, interpolated).each do | frame, ref, actual |
245
+ assert_in_delta ref, actual, D, "At #{frame} Interpolated value should be in delta"
246
+ end
247
+ end
248
+ end
249
+
250
+ class TestLinearPrepolate < Test::Unit::TestCase
251
+ def test_fail
252
+ flunk
253
+ end
254
+ end
255
+
256
+ class TestLinearExtrapolate < Test::Unit::TestCase
257
+ def test_fail
258
+ flunk
259
+ end
260
+ end
261
+
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flame_channel_parser
3
+ version: !ruby/object:Gem::Version
4
+ hash: 17
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 1
9
+ - 1
10
+ version: 1.1.1
11
+ platform: ruby
12
+ authors:
13
+ - Julik Tarkhanov
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-05-17 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: hoe
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 41
30
+ segments:
31
+ - 2
32
+ - 9
33
+ - 1
34
+ version: 2.9.1
35
+ type: :development
36
+ version_requirements: *id001
37
+ description: Includes a small library for parsing and baking anmation curves made on Discrodesk Floke/Inflinto, also known as flame.
38
+ email:
39
+ - me@julik.nl
40
+ executables: []
41
+
42
+ extensions: []
43
+
44
+ extra_rdoc_files:
45
+ - History.txt
46
+ - Manifest.txt
47
+ - README.rdoc
48
+ files:
49
+ - .autotest
50
+ - History.txt
51
+ - Manifest.txt
52
+ - README.rdoc
53
+ - Rakefile
54
+ - lib/flame_channel_parser.rb
55
+ - lib/interpolator.rb
56
+ - lib/parser_2011.rb
57
+ - lib/parser_2012.rb
58
+ - lib/segments.rb
59
+ - plots.numbers
60
+ - plots_2012.numbers
61
+ - test/baked.csv
62
+ - test/channel_with_constants.dat
63
+ - test/curve.csv
64
+ - test/sample_channel.dat
65
+ - test/snaps/FLEM_BrokenTangents.action
66
+ - test/snaps/FLEM_advanced_curve.png
67
+ - test/snaps/FLEM_advanced_curve_example_FL2012.action
68
+ - test/snaps/FLEM_baked_curve.png
69
+ - test/snaps/FLEM_curves_example.action
70
+ - test/snaps/FLEM_curves_example_migrated_to_2012.action
71
+ - test/snaps/FLEM_std_curve.png
72
+ - test/snaps/TW.timewarp
73
+ - test/test_flame_channel_parser.rb
74
+ - test/test_interpolator.rb
75
+ - test/test_segments.rb
76
+ - .gemtest
77
+ has_rdoc: true
78
+ homepage: http://guerilla-di.org/flame-channel-parser
79
+ licenses: []
80
+
81
+ post_install_message:
82
+ rdoc_options:
83
+ - --main
84
+ - README.rdoc
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ hash: 3
93
+ segments:
94
+ - 0
95
+ version: "0"
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ hash: 3
102
+ segments:
103
+ - 0
104
+ version: "0"
105
+ requirements: []
106
+
107
+ rubyforge_project: flame_channel_parser
108
+ rubygems_version: 1.4.1
109
+ signing_key:
110
+ specification_version: 3
111
+ summary: Includes a small library for parsing and baking anmation curves made on Discrodesk Floke/Inflinto, also known as flame.
112
+ test_files:
113
+ - test/test_flame_channel_parser.rb
114
+ - test/test_interpolator.rb
115
+ - test/test_segments.rb