tracksperanto 3.3.6 → 3.3.7
Sign up to get free protection for your applications and to get access to all the features.
- data/{DEVELOPER_DOCS.rdoc → CONTRIBUTING.md} +59 -58
- data/Gemfile +2 -3
- data/History.txt +5 -0
- data/README.rdoc +3 -3
- data/bin/tracksperanto +4 -2
- data/lib/import/base.rb +2 -2
- data/lib/import/flame_stabilizer.rb +37 -28
- data/lib/import/nuke_script.rb +19 -2
- data/lib/import/pftrack.rb +3 -1
- data/lib/import/shake_script.rb +2 -1
- data/lib/tracksperanto.rb +1 -1
- data/lib/tracksperanto/block_init.rb +2 -1
- data/lib/tracksperanto/keyframe.rb +4 -4
- data/test/export/test_boujou_export.rb +1 -1
- data/test/export/test_flame_stabilizer_export.rb +2 -2
- data/test/import/README.rdoc +10 -0
- data/test/import/test_flame_import.rb +3 -3
- data/test/import/test_match_mover_import.rb +9 -0
- data/test/import/test_nuke_import.rb +27 -1
- data/test/test_block_init.rb +49 -0
- data/tracksperanto.gemspec +9 -12
- metadata +9 -25
- data/test/import/README_SAMPLES.txt +0 -5
@@ -1,11 +1,11 @@
|
|
1
|
-
|
1
|
+
## Hacking Tracksperanto
|
2
2
|
|
3
|
-
|
3
|
+
### Tests
|
4
4
|
|
5
5
|
Tracksperanto is heavily tested. Please use the Github checkout to also receive some 17+ megabytes of test files that the test suite
|
6
6
|
can chew on. Contributions or patches without tests will be rejected at sight.
|
7
7
|
|
8
|
-
|
8
|
+
### Development environment
|
9
9
|
|
10
10
|
Tracksperanto is currently being developed on Ruby 1.9.3 but it should also work fine on 1.8.7.
|
11
11
|
What you will need is everything mentioned in the Gemfile plus Bundler.
|
@@ -16,13 +16,13 @@ The test corpus on Tracksperanto is HUGE at the moment, and it makes no sense to
|
|
16
16
|
|
17
17
|
So, to get started:
|
18
18
|
|
19
|
-
* Make sure you have Ruby and Bundler (
|
19
|
+
* Make sure you have Ruby and Bundler (`sudo gem install bundler` if unsure)
|
20
20
|
* Checkout the repo at http://github.com/guerilla-di/tracksperanto
|
21
|
-
* Run
|
21
|
+
* Run `bundle install` and `bundle exec rake` to run the tests
|
22
22
|
* Do your thing, in a separate branch
|
23
|
-
* File a pull request or send a patch to
|
23
|
+
* File a pull request or send a patch to **me at julik dot nl**
|
24
24
|
|
25
|
-
|
25
|
+
### Internal tracker representation
|
26
26
|
|
27
27
|
The trackers are represented by Tracker objects, which work like addressable hashes per frame number. The Tracker objects
|
28
28
|
contain Keyframe objects, and those in turn contain coordinates. The coordinates are stored in absolute pixels, relative to
|
@@ -31,80 +31,81 @@ the zero coordinate in the lower left corner.
|
|
31
31
|
Note on subpixel precision: the absolute left/bottom of the image has coordinates 0,0
|
32
32
|
(at the lower left corner of the leftmost bottommost pixel) and 0.5x0.5 in the middle of that pixel.
|
33
33
|
|
34
|
-
|
34
|
+
### Importing your own formats
|
35
35
|
|
36
36
|
To write an import module refer to Tracksperanto::Import::Base
|
37
37
|
docs. Your importer will be configured with width and height of the comp that it is importing, and will get an IO
|
38
38
|
object with the file that you are processing. You should then yield parsed trackers within the each method (tracker objects should
|
39
39
|
be Tracksperanto::Tracker objects or compatibles)
|
40
40
|
|
41
|
-
|
41
|
+
### Exporting your own formats
|
42
42
|
|
43
43
|
You can easily write an exporter. Refer to the Tracksperanto::Export::Base docs. Note that your exporter should be able to chew alot of data
|
44
44
|
(hundreds of trackers with thousands of keyframes with exported files growing up to 5-10 megs in size are not uncommon!). This means that
|
45
45
|
the exporter should work with streams (smaller parts of the file being exported will be held in memory at a time).
|
46
46
|
|
47
|
-
|
47
|
+
### Ading your own processing steps
|
48
48
|
|
49
49
|
You probably want to write a Tool (consult the Tracksperanto::Tool::Base docs) if you need some processing applied to the tracks
|
50
50
|
or their data. A Tool is just like an export module, except that instead it sits between the exporter and the exporting routine. Tools wrap export
|
51
51
|
modules or each other, so you can stack different tool modules together (like "scale first, then move").
|
52
52
|
|
53
|
-
|
53
|
+
### Writing your own processing pipelines from start to finish
|
54
54
|
|
55
55
|
You probably want to write a descendant of Tracksperanto::Pipeline::Base. This is a class that manages a conversion from start to finish, including detecting the
|
56
56
|
input format, allocating output files and building a chain of Tools to process the export. If you want to make a GUI for Tracksperanto you will likely need
|
57
57
|
to write your own Pipeline class or reimplement parts of it.
|
58
58
|
|
59
|
-
|
59
|
+
### Reporting status from long-running operations
|
60
60
|
|
61
61
|
Almost every module in Tracksperanto has a method called report_progress. This method is used to notify an external callback of what you are doing, and helps keep
|
62
62
|
the software user-friendly. A well-behaved Tracksperanto module should manage it's progress reports properly.
|
63
63
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
64
|
+
### Sample script
|
65
|
+
|
66
|
+
require "rubygems"
|
67
|
+
require "tracksperanto"
|
68
|
+
|
69
|
+
include Tracksperanto
|
70
|
+
|
71
|
+
# Create the importer object, for example for a Shake script.
|
72
|
+
# get_importer will give you the good class even you get the capitalization
|
73
|
+
# wrong!
|
74
|
+
some_importer = Tracksperanto.get_importer("shakescript").new
|
75
|
+
|
76
|
+
# This importer needs to know width and height
|
77
|
+
some_importer.width = 1024
|
78
|
+
some_importer.height = 576
|
79
|
+
some_importer.io = File.open("source_file.shk")
|
80
|
+
|
81
|
+
# The importer responds to each() so if your file is not too big you can just load all the trackers
|
82
|
+
# as an array. If you expect to have alot of trackers investigate a way to buffer them on disk
|
83
|
+
# instead (see Obuf)
|
84
|
+
trackers = some_importer.to_a
|
85
|
+
|
86
|
+
# Create the exporter and pass the output file to it
|
87
|
+
destination_file = File.open("exported_file.other", "wb")
|
88
|
+
some_exporter = Tracksperanto.get_exporter("flamestabilizer").new(destination_file)
|
89
|
+
|
90
|
+
# Now add some tools, for example a Scale
|
91
|
+
scaler = Tool::Scaler.new(some_exporter, :x_factor => 2)
|
92
|
+
# ... and a slip. Tools wrap exporters and other tools, so you can chain them
|
93
|
+
# ad nauseam
|
94
|
+
slipper = Tool::Slipper.new(scaler, :offset => 2)
|
95
|
+
|
96
|
+
# Now when we send export commands to the Slipper it will play them through
|
97
|
+
# to the Scaler and the Scaler in turn will send commands to the exporter.
|
98
|
+
# As you can see when you run export commands you do not have to use the Tracker
|
99
|
+
# objects, you just have to stream the right arguments in the right sequence
|
100
|
+
slipper.start_export(1024, 576)
|
101
|
+
trackers.each do | t |
|
102
|
+
slipper.start_tracker_segment(t.name)
|
103
|
+
t.each do | keyframe |
|
104
|
+
slipper.export_point(keyframe.frame, keyframe.abs_x, keyframe.abs_y, keyframe.residual)
|
105
|
+
end
|
106
|
+
slipper.end_tracker_segment
|
105
107
|
end
|
106
|
-
slipper.
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
# And we are done!
|
108
|
+
slipper.end_export
|
109
|
+
|
110
|
+
# And we are done!
|
111
|
+
|
data/Gemfile
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- ruby -*-
|
2
|
-
source
|
2
|
+
source 'http://rubygems.org'
|
3
3
|
|
4
4
|
gem "bundler"
|
5
5
|
|
@@ -19,12 +19,11 @@ group :development do
|
|
19
19
|
gem "linebyline"
|
20
20
|
|
21
21
|
if RUBY_VERSION > "1.8"
|
22
|
-
gem "flexmock", "~> 1.3", :require => %w( flexmock flexmock/test_unit )
|
22
|
+
gem "flexmock", "~> 1.3.2", :require => %w( flexmock flexmock/test_unit )
|
23
23
|
else
|
24
24
|
gem "flexmock", "~> 0.8", :require => %w( flexmock flexmock/test_unit )
|
25
25
|
end
|
26
26
|
|
27
27
|
gem "cli_test", "~>1.0"
|
28
28
|
gem "rake-hooks"
|
29
|
-
gem "ruby-prof"
|
30
29
|
end
|
data/History.txt
CHANGED
data/README.rdoc
CHANGED
@@ -52,7 +52,7 @@ that you export - and you can apply multiple transformations if desired.
|
|
52
52
|
== Using Tracksperanto from the command line
|
53
53
|
|
54
54
|
To run on your own computer, make sure you have Ruby installed. Versions from 1.8.7
|
55
|
-
and up are supported.
|
55
|
+
and up are supported. Wea re also testing on Ruby 2.0.0 now.
|
56
56
|
|
57
57
|
$ ruby -v
|
58
58
|
ruby 1.9.3p286 (2012-10-12 revision 37165) [x86_64-darwin12.2.0]
|
@@ -100,7 +100,7 @@ If you want your own copy of the web application at your facility we can discuss
|
|
100
100
|
* MatchMover REALVIZ Ascii Point Tracks .rz2 file
|
101
101
|
* MatchMover RZML .rzml file
|
102
102
|
* Maya Live track export file
|
103
|
-
* Nuke .nk script file with Tracker, Reconcile3D and
|
103
|
+
* Nuke .nk script file with Tracker, Reconcile3D, PlanarTracker and CornerPin nodes
|
104
104
|
* PFTrack/PFMatchit .2dt file
|
105
105
|
* Shake .shk script file
|
106
106
|
* Shake .txt tracker file and Nuke CameraTracker auto tracks export
|
@@ -139,7 +139,7 @@ Consult the --help option to see what is available.
|
|
139
139
|
== Development
|
140
140
|
|
141
141
|
If you are interested in reusing Tracksperanto's code or adding modules to the software consult
|
142
|
-
the {short developer introduction}[https://github.com/guerilla-di/tracksperanto/blob/master/
|
142
|
+
the {short developer introduction}[https://github.com/guerilla-di/tracksperanto/blob/master/CONTRIBUTING.md]
|
143
143
|
|
144
144
|
== Limitations
|
145
145
|
|
data/bin/tracksperanto
CHANGED
@@ -10,6 +10,9 @@
|
|
10
10
|
# == Author
|
11
11
|
# Julik <me@julik.nl>
|
12
12
|
|
13
|
+
# Show the message just in case
|
14
|
+
$stdout.puts "Starting Tracksperanto. For information and support please contact info#{64.chr}guerilla-di.org"
|
15
|
+
|
13
16
|
# Require the xperanto lib, which in turn requires Bundler and pulls in all the gems
|
14
17
|
require File.dirname(__FILE__) + '/../lib/tracksperanto' unless defined?(Tracksperanto)
|
15
18
|
require 'update_hints'
|
@@ -17,8 +20,7 @@ require 'optparse'
|
|
17
20
|
require 'progressbar'
|
18
21
|
|
19
22
|
def disclaimer
|
20
|
-
"Please consider a small donation to keep Tracksperanto going: http://guerilla-di.org/source-and-license
|
21
|
-
"For information and support please contact info#{64.chr}guerilla-di.org"
|
23
|
+
"Please consider a small donation to keep Tracksperanto going: http://guerilla-di.org/source-and-license/"
|
22
24
|
end
|
23
25
|
|
24
26
|
options = {}
|
data/lib/import/base.rb
CHANGED
@@ -22,7 +22,7 @@ class Tracksperanto::Import::Base
|
|
22
22
|
# Trakcksperanto will assign the passed width and height to the importer object before running
|
23
23
|
# the import. If not, you can replace the assigned values with your own. At the end of the import
|
24
24
|
# procedure, Tracksperanto will read the values from you again and will use the read values
|
25
|
-
# for determining the original comp size. +width+ and +height+ MUST return integer values after
|
25
|
+
# for determining the original comp size. +width+ and +height+ MUST return unsigned integer values after
|
26
26
|
# the import completes
|
27
27
|
attr_accessor :width, :height
|
28
28
|
|
@@ -64,7 +64,7 @@ class Tracksperanto::Import::Base
|
|
64
64
|
end
|
65
65
|
|
66
66
|
# The main method of the parser. Should
|
67
|
-
# yield each
|
67
|
+
# yield each Tracker that has been fully parsed. After calling this method the caller can ask for
|
68
68
|
# width and height as well.
|
69
69
|
def each
|
70
70
|
end
|
@@ -65,28 +65,41 @@ class Tracksperanto::Import::FlameStabilizer < Tracksperanto::Import::Base
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
+
# Extracts the animation channels and stores them in Obufs
|
69
|
+
# keyed by the channel path (like "tracker1/ref/x")
|
68
70
|
def extract_channels_from_stream(io)
|
69
71
|
parser = StabilizerParser.new
|
70
72
|
parser.logger_proc = method(:report_progress)
|
71
73
|
|
72
|
-
|
73
|
-
names = []
|
74
|
+
channel_map = {}
|
74
75
|
parser.parse(io) do | channel |
|
75
|
-
|
76
|
-
|
76
|
+
# Serialize the channel and store it on disk.
|
77
|
+
# Flame stabilizers are NOT likely to contain hundreds of
|
78
|
+
# trackers unless they were machine-exported from something,
|
79
|
+
# but we need to be memory-aware when we do things like this.
|
80
|
+
# On our test suite we lose half a second on disk IO overhead
|
81
|
+
# of the Obuf here, which is an acceptable compromise.
|
82
|
+
# To get rid of the disk-based cache just toss the outer
|
83
|
+
# Obuf constructor and pass in an Array
|
84
|
+
channel_map[channel.path] = Obuf.new([channel])
|
77
85
|
end
|
78
86
|
|
79
|
-
|
87
|
+
channel_map
|
80
88
|
end
|
81
89
|
|
82
|
-
def scavenge_trackers_from_channels(
|
83
|
-
|
84
|
-
|
90
|
+
def scavenge_trackers_from_channels(channel_map, names)
|
91
|
+
# Use Hash#keys.sort because we want a consistent export order
|
92
|
+
# irregardless of the Ruby version in use
|
93
|
+
# (hash keys are ordered on 1.9 and not ordered on 1.8)
|
94
|
+
channel_map.keys.sort.each do |c|
|
95
|
+
next unless c =~ /\/ref\/x$/
|
85
96
|
|
86
|
-
report_progress("Detected reference channel #{c.
|
97
|
+
report_progress("Detected reference channel #{c.inspect}")
|
87
98
|
|
88
|
-
|
89
|
-
|
99
|
+
extracted_tracker = grab_tracker(channel_map, c)
|
100
|
+
if extracted_tracker
|
101
|
+
yield(extracted_tracker)
|
102
|
+
end
|
90
103
|
end
|
91
104
|
end
|
92
105
|
|
@@ -94,29 +107,25 @@ class Tracksperanto::Import::FlameStabilizer < Tracksperanto::Import::Base
|
|
94
107
|
chan.map{|key| [key.frame, key.value]}
|
95
108
|
end
|
96
109
|
|
97
|
-
def grab_tracker(
|
98
|
-
t = Tracksperanto::Tracker.new(:name =>
|
110
|
+
def grab_tracker(channel_map, ref_x_channel_name)
|
111
|
+
t = Tracksperanto::Tracker.new(:name => ref_x_channel_name.split('/').shift)
|
99
112
|
|
100
113
|
report_progress("Extracting tracker #{t.name}")
|
101
114
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
shift_y_idx = names.index("#{t.name}/shift/y")
|
107
|
-
|
108
|
-
track_y = channels[ref_idx]
|
109
|
-
shift_x = channels[shift_x_idx]
|
110
|
-
shift_y = channels[shift_y_idx]
|
115
|
+
shift_x = channel_map["#{t.name}/shift/x"][0]
|
116
|
+
shift_y = channel_map["#{t.name}/shift/y"][0]
|
117
|
+
ref_x = channel_map["#{t.name}/ref/x"][0]
|
118
|
+
ref_y = channel_map["#{t.name}/ref/y"][0]
|
111
119
|
|
120
|
+
# Collapse separate X and Y curves into series of XY values
|
112
121
|
shift_tuples = zip_curve_tuples(channel_to_frames_and_values(shift_x), channel_to_frames_and_values(shift_y))
|
113
|
-
|
122
|
+
ref_tuples = zip_curve_tuples(channel_to_frames_and_values(ref_x), channel_to_frames_and_values(ref_y))
|
114
123
|
|
115
124
|
# If the channels are just empty go to next tracker
|
116
|
-
return if shift_tuples.empty? ||
|
125
|
+
return if shift_tuples.empty? || ref_tuples.empty?
|
117
126
|
|
118
127
|
report_progress("Detecting base value")
|
119
|
-
base_x, base_y = find_base_x_and_y(
|
128
|
+
base_x, base_y = find_base_x_and_y(ref_tuples, shift_tuples)
|
120
129
|
|
121
130
|
total_kf = 1
|
122
131
|
t.keyframes = shift_tuples.map do | (at, x, y) |
|
@@ -131,10 +140,10 @@ class Tracksperanto::Import::FlameStabilizer < Tracksperanto::Import::Base
|
|
131
140
|
return t
|
132
141
|
end
|
133
142
|
|
134
|
-
def find_base_x_and_y(
|
135
|
-
|
143
|
+
def find_base_x_and_y(ref_tuples, shift_tuples)
|
144
|
+
base_ref_tuple = ref_tuples.find do | track_tuple |
|
136
145
|
shift_tuples.find { |shift_tuple| shift_tuple[0] == track_tuple[0] }
|
137
146
|
end
|
138
|
-
(
|
147
|
+
(base_ref_tuple || ref_tuples[0])[1..2]
|
139
148
|
end
|
140
149
|
end
|
data/lib/import/nuke_script.rb
CHANGED
@@ -5,7 +5,7 @@ require 'tickly'
|
|
5
5
|
class Tracksperanto::Import::NukeScript < Tracksperanto::Import::Base
|
6
6
|
|
7
7
|
def self.human_name
|
8
|
-
"Nuke .nk script file with Tracker, Reconcile3D and
|
8
|
+
"Nuke .nk script file with Tracker, Reconcile3D, PlanarTracker and CornerPin nodes"
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.distinct_file_ext
|
@@ -13,7 +13,8 @@ class Tracksperanto::Import::NukeScript < Tracksperanto::Import::Base
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def self.known_snags
|
16
|
-
'The only supported nodes that we can extract tracks from are Reconcile3D,
|
16
|
+
'The only supported nodes that we can extract tracks from are Reconcile3D,'
|
17
|
+
+ ' PlanarTracker and Tracker (supported Nuke versions are 5, 6 and 7)'
|
17
18
|
end
|
18
19
|
|
19
20
|
def each
|
@@ -21,7 +22,9 @@ class Tracksperanto::Import::NukeScript < Tracksperanto::Import::Base
|
|
21
22
|
parser.add_node_handler_class(Tracker3)
|
22
23
|
parser.add_node_handler_class(Reconcile3D)
|
23
24
|
parser.add_node_handler_class(PlanarTracker1_0)
|
25
|
+
parser.add_node_handler_class(PlanarTracker)
|
24
26
|
parser.add_node_handler_class(Tracker4)
|
27
|
+
parser.add_node_handler_class(CornerPin2D)
|
25
28
|
|
26
29
|
parser.parse(@io) do | node |
|
27
30
|
node.trackers.each do | t |
|
@@ -87,12 +90,26 @@ class Tracksperanto::Import::NukeScript < Tracksperanto::Import::Base
|
|
87
90
|
end
|
88
91
|
end
|
89
92
|
|
93
|
+
# Planar tracker in Nuke 6
|
90
94
|
class PlanarTracker1_0 < Tracker3
|
91
95
|
def point_channels
|
92
96
|
%w( outputBottomLeft outputBottomRight outputTopLeft outputTopRight)
|
93
97
|
end
|
94
98
|
end
|
95
99
|
|
100
|
+
# Planar tracker in Nuke 7
|
101
|
+
class PlanarTracker < PlanarTracker1_0
|
102
|
+
def point_channels
|
103
|
+
%w( outputBottomLeft outputBottomRight outputTopLeft outputTopRight)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class CornerPin2D < Tracker3
|
108
|
+
def point_channels
|
109
|
+
%w( to1 to2 to3 to4 )
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
96
113
|
class Tracker4 < Tracker3
|
97
114
|
|
98
115
|
def initialize(options)
|
data/lib/import/pftrack.rb
CHANGED
@@ -76,7 +76,9 @@ class Tracksperanto::Import::PFTrack < Tracksperanto::Import::Base
|
|
76
76
|
(1..num_of_keyframes).map do | keyframe_idx |
|
77
77
|
report_progress("Reading keyframe #{keyframe_idx} of #{num_of_keyframes} in #{t.name}")
|
78
78
|
f, x, y, residual = io.gets.chomp.split
|
79
|
-
t.keyframe!(:frame => f.to_f - 1,
|
79
|
+
t.keyframe!(:frame => f.to_f - 1,
|
80
|
+
:abs_x => from_pfcoord(x), :abs_y => from_pfcoord(y),
|
81
|
+
:residual => residual.to_f * 8)
|
80
82
|
end
|
81
83
|
end
|
82
84
|
|
data/lib/import/shake_script.rb
CHANGED
@@ -13,7 +13,8 @@ class Tracksperanto::Import::ShakeScript < Tracksperanto::Import::Base
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def self.known_snags
|
16
|
-
'Expressions in node parameters may cause parse errors or incomplete imports.
|
16
|
+
'Expressions in node parameters may cause parse errors or incomplete imports. ' +
|
17
|
+
'Take care to remove expressions or nodes containing them first.'
|
17
18
|
end
|
18
19
|
|
19
20
|
def each
|
data/lib/tracksperanto.rb
CHANGED
@@ -2,7 +2,8 @@
|
|
2
2
|
# Implements the conventional constructor with "hash of attributes" and block support
|
3
3
|
module Tracksperanto::BlockInit
|
4
4
|
def initialize(object_attribute_hash = {})
|
5
|
-
|
5
|
+
m = method(respond_to?(:public_send) ? :public_send : :send)
|
6
|
+
object_attribute_hash.map { |(k, v)| m.call("#{k}=", v) }
|
6
7
|
yield(self) if block_given?
|
7
8
|
end
|
8
9
|
end
|
@@ -9,16 +9,16 @@
|
|
9
9
|
class Tracksperanto::Keyframe
|
10
10
|
include Tracksperanto::Casts, Tracksperanto::BlockInit, Comparable
|
11
11
|
|
12
|
-
#
|
12
|
+
# Integer frame where this keyframe is placed, 0-based
|
13
13
|
attr_accessor :frame
|
14
14
|
|
15
|
-
#
|
15
|
+
# Float X value of the point, zero is lower left
|
16
16
|
attr_accessor :abs_x
|
17
17
|
|
18
|
-
#
|
18
|
+
# Float Y value of the point, zero is lower left
|
19
19
|
attr_accessor :abs_y
|
20
20
|
|
21
|
-
#
|
21
|
+
# Float residual (0 is "spot on")
|
22
22
|
attr_accessor :residual
|
23
23
|
|
24
24
|
cast_to_float :abs_x, :abs_y, :residual
|
@@ -7,7 +7,7 @@ class BoujouExportTest < Test::Unit::TestCase
|
|
7
7
|
|
8
8
|
def test_export_output_written
|
9
9
|
t = Time.local(2010, "Apr", 15, 17, 21, 26)
|
10
|
-
flexmock(Time).should_receive(:now).
|
10
|
+
flexmock(Time).should_receive(:now).and_return(t)
|
11
11
|
ensure_same_output Tracksperanto::Export::Boujou, P
|
12
12
|
end
|
13
13
|
|
@@ -1,13 +1,13 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
2
|
require File.expand_path(File.dirname(__FILE__)) + '/../helper'
|
3
3
|
|
4
|
-
class
|
4
|
+
class TestFlameStabilizerExport < Test::Unit::TestCase
|
5
5
|
include ParabolicTracks
|
6
6
|
P = File.dirname(__FILE__) + "/samples/ref_flame.stabilizer"
|
7
7
|
|
8
8
|
def test_export_output_written
|
9
9
|
t = Time.local(2010, "Feb", 18, 17, 22, 12)
|
10
|
-
flexmock(Time).should_receive(:now).
|
10
|
+
flexmock(Time).should_receive(:now).and_return(t)
|
11
11
|
ensure_same_output Tracksperanto::Export::FlameStabilizer, P
|
12
12
|
end
|
13
13
|
|
@@ -0,0 +1,10 @@
|
|
1
|
+
Tracksperanto has a huge test corpus of test files, which is stored in the project's Github repo.
|
2
|
+
|
3
|
+
This is why the repo is so big.
|
4
|
+
|
5
|
+
However, most users of Tracksperanto are actually _users_, they won't need
|
6
|
+
all the testing data. And without this data, tracksperanto is less than
|
7
|
+
100 kilobytes in size.
|
8
|
+
|
9
|
+
If you intend to actually write code that uses Tracksperanto or to fix
|
10
|
+
a bug, you will most definitely need all the test data. In that case, just do a git checkout.
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
2
|
require File.expand_path(File.dirname(__FILE__)) + '/../helper'
|
3
3
|
|
4
|
-
class
|
4
|
+
class TestFlameImport < Test::Unit::TestCase
|
5
5
|
DELTA = 0.1
|
6
6
|
|
7
7
|
def test_parsing_from_flame
|
@@ -105,8 +105,8 @@ class FlameImportTest < Test::Unit::TestCase
|
|
105
105
|
def test_bilinear_passes_proper_naming
|
106
106
|
fixture = File.open(File.dirname(__FILE__) + '/samples/flame_stabilizer/cornerpin_2012.stabilizer')
|
107
107
|
trackers = Tracksperanto::Import::FlameStabilizer.new(:io => fixture).to_a
|
108
|
-
|
109
|
-
assert_equal
|
108
|
+
tracker_order = ["bottom_left", "bottom_right", "top_left", "top_right"]
|
109
|
+
assert_equal tracker_order, trackers.map(&:name)
|
110
110
|
end
|
111
111
|
|
112
112
|
end
|
@@ -6,6 +6,7 @@ class MatchMoverImportTest < Test::Unit::TestCase
|
|
6
6
|
|
7
7
|
P = File.dirname(__FILE__) + '/samples/match_mover/kipPointsMatchmover.rz2'
|
8
8
|
P2 = File.dirname(__FILE__) + '/samples/match_mover/NonSequentialMatchmoverPoints.rz2'
|
9
|
+
P3 = File.dirname(__FILE__) + '/samples/match_mover/cha_171_1020_atb_v001.rz2'
|
9
10
|
|
10
11
|
def test_introspects_properly
|
11
12
|
i = Tracksperanto::Import::MatchMover
|
@@ -22,6 +23,14 @@ class MatchMoverImportTest < Test::Unit::TestCase
|
|
22
23
|
assert_equal 0, trackers[0][0].frame, "Should have offset the first frame to 0"
|
23
24
|
end
|
24
25
|
|
26
|
+
def test_parsing_case_nil_exception
|
27
|
+
fixture = File.open(P3)
|
28
|
+
|
29
|
+
parser = Tracksperanto::Import::MatchMover.new(:io => fixture)
|
30
|
+
trackers = parser.to_a
|
31
|
+
assert_equal 6, trackers.length
|
32
|
+
end
|
33
|
+
|
25
34
|
def test_parsing_from_matchmover
|
26
35
|
fixture = File.open(P)
|
27
36
|
|
@@ -6,7 +6,7 @@ class NukeImportTest < Test::Unit::TestCase
|
|
6
6
|
|
7
7
|
def test_introspects_properly
|
8
8
|
i = Tracksperanto::Import::NukeScript
|
9
|
-
assert_equal "Nuke .nk script file with Tracker, Reconcile3D and
|
9
|
+
assert_equal "Nuke .nk script file with Tracker, Reconcile3D, PlanarTracker and CornerPin nodes", i.human_name
|
10
10
|
assert !i.autodetects_size?
|
11
11
|
end
|
12
12
|
|
@@ -34,6 +34,17 @@ class NukeImportTest < Test::Unit::TestCase
|
|
34
34
|
assert_equal 128, trackers[0].length
|
35
35
|
end
|
36
36
|
|
37
|
+
def test_parsing_cornerpin
|
38
|
+
fixture = File.open(File.dirname(__FILE__) + '/samples/nuke/cornerpin.nk')
|
39
|
+
|
40
|
+
parser = Tracksperanto::Import::NukeScript.new(:io => fixture)
|
41
|
+
parser.width = 4096
|
42
|
+
parser.height = 2304
|
43
|
+
|
44
|
+
trackers = parser.to_a
|
45
|
+
assert_equal 4, trackers.length
|
46
|
+
end
|
47
|
+
|
37
48
|
def test_parsing_planar_tracker
|
38
49
|
fixture = File.open(File.dirname(__FILE__) + '/samples/nuke/planar.nk')
|
39
50
|
|
@@ -49,6 +60,21 @@ class NukeImportTest < Test::Unit::TestCase
|
|
49
60
|
assert_equal ref_names, trackers.map{|e| e.name }
|
50
61
|
end
|
51
62
|
|
63
|
+
def test_parsing_planar_tracker_nuke7
|
64
|
+
fixture = File.open(File.dirname(__FILE__) + '/samples/nuke/nuke7_planar.nk')
|
65
|
+
|
66
|
+
parser = Tracksperanto::Import::NukeScript.new(:io => fixture)
|
67
|
+
parser.width = 1920
|
68
|
+
parser.height = 1080
|
69
|
+
|
70
|
+
trackers = parser.to_a
|
71
|
+
assert_equal 4, trackers.length
|
72
|
+
|
73
|
+
ref_names = %w( PlanarTracker1_outputBottomLeft PlanarTracker1_outputBottomRight
|
74
|
+
PlanarTracker1_outputTopLeft PlanarTracker1_outputTopRight )
|
75
|
+
assert_equal ref_names, trackers.map{|e| e.name }
|
76
|
+
end
|
77
|
+
|
52
78
|
def test_parsing_from_nuke
|
53
79
|
fixture = File.open(File.dirname(__FILE__) + '/samples/nuke/one_tracker_with_break.nk')
|
54
80
|
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require File.expand_path(File.dirname(__FILE__)) + '/helper'
|
3
|
+
|
4
|
+
class TestBlockInit < Test::Unit::TestCase
|
5
|
+
|
6
|
+
class Settable
|
7
|
+
include Tracksperanto::BlockInit
|
8
|
+
|
9
|
+
attr_accessor :foo, :bar
|
10
|
+
|
11
|
+
private
|
12
|
+
def privatized=(something)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_block_init_with_hash
|
17
|
+
s = Settable.new(:foo => "x", :bar => "y")
|
18
|
+
assert_equal "x", s.foo
|
19
|
+
assert_equal "y", s.bar
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_block_init_with_hash_raises_on_unknown_attribute
|
23
|
+
assert_raise(NoMethodError) { Settable.new(:nonexistent => true) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_block_init_with_block_yields_the_object
|
27
|
+
within_blk = nil
|
28
|
+
s = Settable.new do | f |
|
29
|
+
within_blk = f
|
30
|
+
f.foo = "x"
|
31
|
+
end
|
32
|
+
|
33
|
+
assert_equal s, within_blk, "Should have yielded the object to the blk"
|
34
|
+
assert_equal "x", s.foo
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_block_init_attributes_overwrite_hash_attributes
|
38
|
+
s = Settable.new(:foo => "bar") { |f| f.foo = "x" }
|
39
|
+
assert_equal "x", s.foo
|
40
|
+
end
|
41
|
+
|
42
|
+
if RUBY_VERSION > '1.9'
|
43
|
+
def test_block_init_uses_public_send
|
44
|
+
assert_raise(NoMethodError) { Settable.new(:privatized => true) }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
end
|
data/tracksperanto.gemspec
CHANGED
@@ -5,20 +5,19 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "tracksperanto"
|
8
|
-
s.version = "3.3.
|
8
|
+
s.version = "3.3.7"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Julik Tarkhanov"]
|
12
|
-
s.date = "2013-
|
12
|
+
s.date = "2013-07-25"
|
13
13
|
s.description = "Converts 2D track exports between different apps like Flame, MatchMover, PFTrack..."
|
14
14
|
s.email = "me@julik.nl"
|
15
15
|
s.executables = ["tracksperanto"]
|
16
16
|
s.extra_rdoc_files = [
|
17
|
-
"DEVELOPER_DOCS.rdoc",
|
18
17
|
"README.rdoc"
|
19
18
|
]
|
20
19
|
s.files = [
|
21
|
-
"
|
20
|
+
"CONTRIBUTING.md",
|
22
21
|
"Gemfile",
|
23
22
|
"History.txt",
|
24
23
|
"MIT_LICENSE.txt",
|
@@ -141,7 +140,7 @@ Gem::Specification.new do |s|
|
|
141
140
|
"test/export/test_syntheyes_export.rb",
|
142
141
|
"test/export/test_xsi_python_export.rb",
|
143
142
|
"test/helper.rb",
|
144
|
-
"test/import/
|
143
|
+
"test/import/README.rdoc",
|
145
144
|
"test/import/test_3de_import.rb",
|
146
145
|
"test/import/test_3de_import3.rb",
|
147
146
|
"test/import/test_boujou_import.rb",
|
@@ -165,6 +164,7 @@ Gem::Specification.new do |s|
|
|
165
164
|
"test/subpixel/subpixel_grid.sni",
|
166
165
|
"test/subpixel/subpixel_grid.tif",
|
167
166
|
"test/subpixel/sy_subpix_2dpaths.txt",
|
167
|
+
"test/test_block_init.rb",
|
168
168
|
"test/test_buffer_io.rb",
|
169
169
|
"test/test_casts.rb",
|
170
170
|
"test/test_cli.rb",
|
@@ -202,7 +202,7 @@ Gem::Specification.new do |s|
|
|
202
202
|
s.homepage = "http://guerilla-di.org/tracksperanto"
|
203
203
|
s.licenses = ["MIT"]
|
204
204
|
s.require_paths = ["lib"]
|
205
|
-
s.rubygems_version = "1.8.
|
205
|
+
s.rubygems_version = "1.8.25"
|
206
206
|
s.summary = "A universal 2D tracks converter"
|
207
207
|
|
208
208
|
if s.respond_to? :specification_version then
|
@@ -221,10 +221,9 @@ Gem::Specification.new do |s|
|
|
221
221
|
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
222
222
|
s.add_development_dependency(%q<rake>, [">= 0"])
|
223
223
|
s.add_development_dependency(%q<linebyline>, [">= 0"])
|
224
|
-
s.add_development_dependency(%q<flexmock>, ["~> 1.3"])
|
224
|
+
s.add_development_dependency(%q<flexmock>, ["~> 1.3.2"])
|
225
225
|
s.add_development_dependency(%q<cli_test>, ["~> 1.0"])
|
226
226
|
s.add_development_dependency(%q<rake-hooks>, [">= 0"])
|
227
|
-
s.add_development_dependency(%q<ruby-prof>, [">= 0"])
|
228
227
|
else
|
229
228
|
s.add_dependency(%q<bundler>, [">= 0"])
|
230
229
|
s.add_dependency(%q<obuf>, ["~> 1.1"])
|
@@ -238,10 +237,9 @@ Gem::Specification.new do |s|
|
|
238
237
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
239
238
|
s.add_dependency(%q<rake>, [">= 0"])
|
240
239
|
s.add_dependency(%q<linebyline>, [">= 0"])
|
241
|
-
s.add_dependency(%q<flexmock>, ["~> 1.3"])
|
240
|
+
s.add_dependency(%q<flexmock>, ["~> 1.3.2"])
|
242
241
|
s.add_dependency(%q<cli_test>, ["~> 1.0"])
|
243
242
|
s.add_dependency(%q<rake-hooks>, [">= 0"])
|
244
|
-
s.add_dependency(%q<ruby-prof>, [">= 0"])
|
245
243
|
end
|
246
244
|
else
|
247
245
|
s.add_dependency(%q<bundler>, [">= 0"])
|
@@ -256,10 +254,9 @@ Gem::Specification.new do |s|
|
|
256
254
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
257
255
|
s.add_dependency(%q<rake>, [">= 0"])
|
258
256
|
s.add_dependency(%q<linebyline>, [">= 0"])
|
259
|
-
s.add_dependency(%q<flexmock>, ["~> 1.3"])
|
257
|
+
s.add_dependency(%q<flexmock>, ["~> 1.3.2"])
|
260
258
|
s.add_dependency(%q<cli_test>, ["~> 1.0"])
|
261
259
|
s.add_dependency(%q<rake-hooks>, [">= 0"])
|
262
|
-
s.add_dependency(%q<ruby-prof>, [">= 0"])
|
263
260
|
end
|
264
261
|
end
|
265
262
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tracksperanto
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.3.
|
4
|
+
version: 3.3.7
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-07-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -210,7 +210,7 @@ dependencies:
|
|
210
210
|
requirements:
|
211
211
|
- - ~>
|
212
212
|
- !ruby/object:Gem::Version
|
213
|
-
version:
|
213
|
+
version: 1.3.2
|
214
214
|
type: :development
|
215
215
|
prerelease: false
|
216
216
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -218,7 +218,7 @@ dependencies:
|
|
218
218
|
requirements:
|
219
219
|
- - ~>
|
220
220
|
- !ruby/object:Gem::Version
|
221
|
-
version:
|
221
|
+
version: 1.3.2
|
222
222
|
- !ruby/object:Gem::Dependency
|
223
223
|
name: cli_test
|
224
224
|
requirement: !ruby/object:Gem::Requirement
|
@@ -251,22 +251,6 @@ dependencies:
|
|
251
251
|
- - ! '>='
|
252
252
|
- !ruby/object:Gem::Version
|
253
253
|
version: '0'
|
254
|
-
- !ruby/object:Gem::Dependency
|
255
|
-
name: ruby-prof
|
256
|
-
requirement: !ruby/object:Gem::Requirement
|
257
|
-
none: false
|
258
|
-
requirements:
|
259
|
-
- - ! '>='
|
260
|
-
- !ruby/object:Gem::Version
|
261
|
-
version: '0'
|
262
|
-
type: :development
|
263
|
-
prerelease: false
|
264
|
-
version_requirements: !ruby/object:Gem::Requirement
|
265
|
-
none: false
|
266
|
-
requirements:
|
267
|
-
- - ! '>='
|
268
|
-
- !ruby/object:Gem::Version
|
269
|
-
version: '0'
|
270
254
|
description: Converts 2D track exports between different apps like Flame, MatchMover,
|
271
255
|
PFTrack...
|
272
256
|
email: me@julik.nl
|
@@ -274,10 +258,9 @@ executables:
|
|
274
258
|
- tracksperanto
|
275
259
|
extensions: []
|
276
260
|
extra_rdoc_files:
|
277
|
-
- DEVELOPER_DOCS.rdoc
|
278
261
|
- README.rdoc
|
279
262
|
files:
|
280
|
-
-
|
263
|
+
- CONTRIBUTING.md
|
281
264
|
- Gemfile
|
282
265
|
- History.txt
|
283
266
|
- MIT_LICENSE.txt
|
@@ -400,7 +383,7 @@ files:
|
|
400
383
|
- test/export/test_syntheyes_export.rb
|
401
384
|
- test/export/test_xsi_python_export.rb
|
402
385
|
- test/helper.rb
|
403
|
-
- test/import/
|
386
|
+
- test/import/README.rdoc
|
404
387
|
- test/import/test_3de_import.rb
|
405
388
|
- test/import/test_3de_import3.rb
|
406
389
|
- test/import/test_boujou_import.rb
|
@@ -424,6 +407,7 @@ files:
|
|
424
407
|
- test/subpixel/subpixel_grid.sni
|
425
408
|
- test/subpixel/subpixel_grid.tif
|
426
409
|
- test/subpixel/sy_subpix_2dpaths.txt
|
410
|
+
- test/test_block_init.rb
|
427
411
|
- test/test_buffer_io.rb
|
428
412
|
- test/test_casts.rb
|
429
413
|
- test/test_cli.rb
|
@@ -472,7 +456,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
472
456
|
version: '0'
|
473
457
|
segments:
|
474
458
|
- 0
|
475
|
-
hash: -
|
459
|
+
hash: -4537325556160571006
|
476
460
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
477
461
|
none: false
|
478
462
|
requirements:
|
@@ -481,7 +465,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
481
465
|
version: '0'
|
482
466
|
requirements: []
|
483
467
|
rubyforge_project:
|
484
|
-
rubygems_version: 1.8.
|
468
|
+
rubygems_version: 1.8.25
|
485
469
|
signing_key:
|
486
470
|
specification_version: 3
|
487
471
|
summary: A universal 2D tracks converter
|
@@ -1,5 +0,0 @@
|
|
1
|
-
Tracksperanto has a huge test corpus of test files, which is stored in the project's Github repo.
|
2
|
-
Checkout the repo to run tests against these samples.
|
3
|
-
Since most users of Tracksperanto are actually USERS, they do not need to download the 4 megabytes of test fixtures
|
4
|
-
as opposed to 80 kilobytes of the program itself. If you want to develop against Tracksperanto we advise you DO use
|
5
|
-
the test corpus though, so please pretty please just pull it off Github.
|