tracksperanto 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +37 -0
- data/README.txt +56 -0
- data/Rakefile +13 -0
- data/bin/tracksperanto +74 -0
- data/lib/export/base.rb +35 -0
- data/lib/export/flame_stabilizer.rb +50 -0
- data/lib/export/mux.rb +33 -0
- data/lib/export/pftrack.rb +30 -0
- data/lib/export/shake_text.rb +29 -0
- data/lib/export/syntheyes.rb +32 -0
- data/lib/import/base.rb +24 -0
- data/lib/import/flame_stabilizer.rb +34 -0
- data/lib/import/shake_script.rb +127 -0
- data/lib/import/shake_text.rb +29 -0
- data/lib/import/syntheyes.rb +32 -0
- data/lib/middleware/base.rb +28 -0
- data/lib/middleware/scaler.rb +24 -0
- data/lib/middleware/slipper.rb +12 -0
- data/lib/pipeline.rb +54 -0
- data/lib/tracksperanto.rb +131 -0
- data/test/.DS_Store +0 -0
- data/test/helper.rb +5 -0
- data/test/samples/.DS_Store +0 -0
- data/test/samples/flyover2DP_syntheyes.txt +12687 -0
- data/test/samples/megaTrack.action.3dtrack.stabilizer +29793 -0
- data/test/samples/one_shake_tracker.txt +49 -0
- data/test/samples/one_shake_tracker_from_first.txt +188 -0
- data/test/samples/shake_tracker_nodes.shk +921 -0
- data/test/samples/shake_tracker_nodes_to_syntheyes.txt +4091 -0
- data/test/samples/three_tracks_in_one_stabilizer.shk +320 -0
- data/test/samples/two_shake_trackers.txt +78 -0
- data/test/samples/two_tracks_in_one_tracker.shk +319 -0
- data/test/test_flame_block.rb +19 -0
- data/test/test_keyframe.rb +32 -0
- data/test/test_shake_export.rb +58 -0
- data/test/test_shake_script_import.rb +50 -0
- data/test/test_shake_text_import.rb +44 -0
- data/test/test_syntheyes_import.rb +25 -0
- metadata +111 -0
data/Manifest.txt
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
Manifest.txt
|
2
|
+
README.txt
|
3
|
+
Rakefile
|
4
|
+
bin/tracksperanto
|
5
|
+
lib/export/base.rb
|
6
|
+
lib/export/flame_stabilizer.rb
|
7
|
+
lib/export/mux.rb
|
8
|
+
lib/export/pftrack.rb
|
9
|
+
lib/export/shake_text.rb
|
10
|
+
lib/export/syntheyes.rb
|
11
|
+
lib/import/base.rb
|
12
|
+
lib/import/flame_stabilizer.rb
|
13
|
+
lib/import/shake_script.rb
|
14
|
+
lib/import/shake_text.rb
|
15
|
+
lib/import/syntheyes.rb
|
16
|
+
lib/middleware/base.rb
|
17
|
+
lib/middleware/scaler.rb
|
18
|
+
lib/middleware/slipper.rb
|
19
|
+
lib/pipeline.rb
|
20
|
+
lib/tracksperanto.rb
|
21
|
+
test/.DS_Store
|
22
|
+
test/helper.rb
|
23
|
+
test/samples/.DS_Store
|
24
|
+
test/samples/flyover2DP_syntheyes.txt
|
25
|
+
test/samples/megaTrack.action.3dtrack.stabilizer
|
26
|
+
test/samples/one_shake_tracker.txt
|
27
|
+
test/samples/one_shake_tracker_from_first.txt
|
28
|
+
test/samples/shake_tracker_nodes.shk
|
29
|
+
test/samples/shake_tracker_nodes_to_syntheyes.txt
|
30
|
+
test/samples/three_tracks_in_one_stabilizer.shk
|
31
|
+
test/samples/two_shake_trackers.txt
|
32
|
+
test/samples/two_tracks_in_one_tracker.shk
|
33
|
+
test/test_keyframe.rb
|
34
|
+
test/test_shake_export.rb
|
35
|
+
test/test_shake_script_import.rb
|
36
|
+
test/test_shake_text_import.rb
|
37
|
+
test/test_syntheyes_import.rb
|
data/README.txt
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
= Tracksperanto
|
2
|
+
|
3
|
+
* http://guerilla-di.org/tracksperanto
|
4
|
+
|
5
|
+
== Description
|
6
|
+
|
7
|
+
Tracksperanto is a universal 2D-track translator between many apps.
|
8
|
+
|
9
|
+
Import support:
|
10
|
+
* Shake script (one tracker node per tracker)
|
11
|
+
* Shake tracker node export (textfile with many tracks per file), also exported by Boujou and others
|
12
|
+
* PFTrack 2dt files
|
13
|
+
* Syntheyes 2D tracking data exports (UV coordinates)
|
14
|
+
|
15
|
+
Export support:
|
16
|
+
|
17
|
+
* Shake text file (many trackers per file), also accepted by Boujou
|
18
|
+
* PFTrack 2dt file (with residuals)
|
19
|
+
* Syntheyes 2D tracking data import (UV coordinates)
|
20
|
+
|
21
|
+
The main way to use Tracksperanto is to use the supplied "tracksperanto" binary, like so:
|
22
|
+
|
23
|
+
tracksperanto -f ShakeScript -w 1920 -h 1080 /Films/Blockbuster/Shots/001/script.shk
|
24
|
+
|
25
|
+
ShakeScript is the name of the translator that will be used to read the file (many apps export tracks as .txt files so
|
26
|
+
there is no way for us to autodetect them all). -w and -h stand for Width and Height and define the size of your comp (different
|
27
|
+
tracking apps use different coordinate systems and we need to know the size of the comp to properly convert these). You also have
|
28
|
+
additional options like -xs, -ys and --slip - consult the usage info for the tracksperanto binary.
|
29
|
+
|
30
|
+
The converted files will be saved in the same directory as the source, if resulting converted files already exist ++they will be overwritten without warning++.
|
31
|
+
|
32
|
+
== Modularity
|
33
|
+
|
34
|
+
Tracksperanto supports many export and import formats. It also can help when you need to import and export the same format,
|
35
|
+
but you need some operation applied to the result (like scaling a proxy track up). Internally, Tracksperanto talks
|
36
|
+
Exporters, Importers and Middlewares. Any processing chain usually works like this:
|
37
|
+
|
38
|
+
1) The tracker file is read and trackers and their keyframes are extracted, converting them to the internal representation.
|
39
|
+
For some formats you need to supply the width and height of the source material
|
40
|
+
2) The trackers and their keyframes are dumped to all export formats Tracksperanto supports, optionally passing through middleware
|
41
|
+
|
42
|
+
== Internal coordinate system
|
43
|
+
|
44
|
+
Frame numbers start from zero (frame 0 is first frame of the track).
|
45
|
+
|
46
|
+
Tracksperanto uses the Shake coordinates as base. Image is Y-positive, X-positive, absolute pixel values up and right (zero is in the
|
47
|
+
lower left corner). Some apps use a different coordinate system so translation will take place on import or on export, respectively.
|
48
|
+
|
49
|
+
We also use residual and not correlation (residual is how far the tracker strolls away, correlation is how sure the tracker is
|
50
|
+
about what it's doing). Residual is the inverse of correlation (with total correlation of one the residual excursion becomes zero).
|
51
|
+
|
52
|
+
== Limitations
|
53
|
+
|
54
|
+
Information about the search area, reference area and offset is not passed along (outside of scope for the app and different trackers handle
|
55
|
+
these differently, if at all). For some modules no residual will be passed along (3D tracking apps generally do not export residual with
|
56
|
+
backprojected 3D features).
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'hoe'
|
3
|
+
require './lib/tracksperanto'
|
4
|
+
|
5
|
+
|
6
|
+
# Disable spurious warnings when running tests, ActiveMagic cannot stand -w
|
7
|
+
Hoe::RUBY_FLAGS.replace ENV['RUBY_FLAGS'] || "-I#{%w(lib test).join(File::PATH_SEPARATOR)}" +
|
8
|
+
(Hoe::RUBY_DEBUG ? " #{RUBY_DEBUG}" : '')
|
9
|
+
|
10
|
+
Hoe.new('tracksperanto', Tracksperanto::VERSION) do |p|
|
11
|
+
p.rubyforge_name = 'guerilla-di'
|
12
|
+
p.developer('Julik Tarkhanov', 'me@julik.nl')
|
13
|
+
end
|
data/bin/tracksperanto
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# == Synopsis
|
3
|
+
#
|
4
|
+
# Translate a 2D track file from a single format to many others
|
5
|
+
#
|
6
|
+
# == Usage
|
7
|
+
#
|
8
|
+
# tracksperanto -f shakescript /Films/Blockbuster/Shots/001/script.shk -w 1920 -h 1080
|
9
|
+
#
|
10
|
+
# == Author
|
11
|
+
# Julik <me@julik.nl>
|
12
|
+
|
13
|
+
require File.dirname(__FILE__) + '/../lib/tracksperanto'
|
14
|
+
require File.dirname(__FILE__) + '/../lib/pipeline'
|
15
|
+
require 'optparse'
|
16
|
+
|
17
|
+
# Sane defaults
|
18
|
+
reader_klass = Tracksperanto::Import::ShakeScript
|
19
|
+
width = 1920
|
20
|
+
height = 1080
|
21
|
+
scale_x = 1.0
|
22
|
+
scale_y = 1.0
|
23
|
+
slip = 0
|
24
|
+
golden_tracks = false
|
25
|
+
|
26
|
+
readers = Tracksperanto::Import.constants.map{|e| e.to_s }.reject{|e| e == 'Base'}
|
27
|
+
informative_readers = readers.reject{|e| e == 'ShakeScript'}
|
28
|
+
|
29
|
+
parser = OptionParser.new do | p |
|
30
|
+
p.banner = "Usage: tracksperanto -f ShakeScript -w 1920 -h 1080 /Films/Blockbuster/Shots/001/script.shk"
|
31
|
+
p.on(" -f", "--from TRANSLATOR", String, "Use the specific import translator (defaults to ShakeScript, but can be \
|
32
|
+
#{informative_readers.join(', ')})") do | f |
|
33
|
+
begin
|
34
|
+
reader_klass = Tracksperanto::Import.const_get(f)
|
35
|
+
rescue NameError => e
|
36
|
+
reader_list = readers.join("\n\t")
|
37
|
+
STDERR.puts "Unknown reader #{f.inspect}, available readers:\n\t#{readers}"
|
38
|
+
exit(-1)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
p.on(" -w", "--width WIDTH_IN_PIXELS", Integer, "Absolute input comp width in pixels") { |w| width = w }
|
42
|
+
p.on(" -h", "--height HEIGHT_IN_PIXELS", Integer, "Absolute input comp height in pixels") {|w| height = w }
|
43
|
+
p.on(" -xs", "--xscale X_SCALING_FACTOR", Float, "Scale the result in X by this factor (1.0 is the default)") {|sx| scale_x = sx }
|
44
|
+
p.on(" -ys", "--yscale Y_SCALING_FACTOR", Float, "Scale the result in Y by this factor (1.0 is the default)") {|sy| scale_y = sy }
|
45
|
+
p.on(" -s", "--slip FRAMES", Integer, "Slip the result by this number of frames, positive is 'later'") {|sy| slip = sy }
|
46
|
+
p.on(" -g", "--golden", "Reset the residuals of all trackers to 0 (ignore correlation)") {|g_flag|
|
47
|
+
golden_tracks = g_flag
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
begin
|
52
|
+
parser.parse!
|
53
|
+
rescue OptionParser::MissingArgument => e
|
54
|
+
STDERR.puts "Unknown argument: #{e.message}"
|
55
|
+
puts parser
|
56
|
+
exit(-1)
|
57
|
+
end
|
58
|
+
|
59
|
+
input_file = ARGV.pop
|
60
|
+
if !input_file
|
61
|
+
STDERR.puts "No input file provided - should be the last argument"
|
62
|
+
puts parser
|
63
|
+
exit(-1)
|
64
|
+
end
|
65
|
+
|
66
|
+
pipe = Tracksperanto::Pipeline.new
|
67
|
+
pipe.run(input_file, width, height, reader_klass) do | scaler, slipper, golden |
|
68
|
+
slipper.slip = slip
|
69
|
+
scaler.x_factor = scale_x
|
70
|
+
scaler.y_factor = scale_y
|
71
|
+
golden.enabled = golden_tracks
|
72
|
+
end
|
73
|
+
|
74
|
+
puts "Converted #{pipe.converted_points} trackers"
|
data/lib/export/base.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# Base exporter
|
2
|
+
class Tracksperanto::Export::Base
|
3
|
+
|
4
|
+
def self.inherited(by)
|
5
|
+
Tracksperanto.exporters << by
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
# Should return the suffix and extension of this export file (like "_flame.stabilizer"). It's a class
|
10
|
+
# method because it gets requested before the exporter is instantiated
|
11
|
+
def self.desc_and_extension
|
12
|
+
"data.txt"
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(write_to_io)
|
16
|
+
@io = write_to_io
|
17
|
+
end
|
18
|
+
|
19
|
+
# Called on export start
|
20
|
+
def start_export( img_width, img_height)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Called on export end
|
24
|
+
def end_export
|
25
|
+
end
|
26
|
+
|
27
|
+
# Called on tracker start, one for each tracker. Start of the next tracker
|
28
|
+
# signifies that the previous tracker has passed by
|
29
|
+
def start_tracker_segment(tracker_name)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Called for each tracker keyframe
|
33
|
+
def export_point(at_frame_i, abs_float_x, abs_float_y, float_residual)
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class Tracksperanto::Export::FlameStabilizer < Tracksperanto::Export::Base
|
2
|
+
PREAMBLE = '' #__DATA__.read
|
3
|
+
|
4
|
+
# Should return the suffix and extension of this export file (like "_flame.stabilizer")
|
5
|
+
def self.desc_and_extension
|
6
|
+
"flame.stabilizer"
|
7
|
+
end
|
8
|
+
|
9
|
+
def start_export(w, h)
|
10
|
+
@width = w, @height = h
|
11
|
+
end
|
12
|
+
|
13
|
+
def start_tracker_segment(tracker_name)
|
14
|
+
@tracker_count ||= 0
|
15
|
+
@tracker_count += 1
|
16
|
+
end
|
17
|
+
|
18
|
+
def end_export
|
19
|
+
preamble = PREAMBLE % [ @tracker_count, @width, @height]
|
20
|
+
end
|
21
|
+
|
22
|
+
def export_point(frame, abs_float_x, abs_float_y, float_residual)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
__END__
|
27
|
+
StabilizerFileVersion 5.0
|
28
|
+
CreationDate Tue Dec 9 21:02:02 2008
|
29
|
+
|
30
|
+
|
31
|
+
NbTrackers %d
|
32
|
+
Selected 0
|
33
|
+
FrameWidth %d
|
34
|
+
FrameHeight %d
|
35
|
+
AutoKey yes
|
36
|
+
MotionPath yes
|
37
|
+
Icons yes
|
38
|
+
AutoPan no
|
39
|
+
EditMode 1
|
40
|
+
Format 0
|
41
|
+
Padding
|
42
|
+
Red 0
|
43
|
+
Green 0
|
44
|
+
Blue 0
|
45
|
+
Oversampling no
|
46
|
+
Opacity 50
|
47
|
+
Zoom 3
|
48
|
+
Field no
|
49
|
+
Backward no
|
50
|
+
Anim
|
data/lib/export/mux.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# Multiplexor. Does not inherit Base so that it does not get used as a translator
|
2
|
+
class Tracksperanto::Export::Mux
|
3
|
+
attr_accessor :outputs
|
4
|
+
|
5
|
+
def initialize(*outputs)
|
6
|
+
@outputs = outputs.flatten
|
7
|
+
end
|
8
|
+
|
9
|
+
# Called on export start
|
10
|
+
def start_export( img_width, img_height)
|
11
|
+
@outputs.each do | output |
|
12
|
+
output.start_export( img_width, img_height)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Called on tracker start, one for each tracker
|
17
|
+
def start_tracker_segment(tracker_name)
|
18
|
+
@outputs.each do | output |
|
19
|
+
output.start_tracker_segment(tracker_name)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Called for each tracker keyframe
|
24
|
+
def export_point(at_frame_i, abs_float_x, abs_float_y, float_residual)
|
25
|
+
@outputs.each do | output |
|
26
|
+
output.export_point(at_frame_i, abs_float_x, abs_float_y, float_residual)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def end_export
|
31
|
+
@outputs.each{|o| o.end_export }
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Tracksperanto::Export::Pftrack < Tracksperanto::Export::Base
|
2
|
+
|
3
|
+
# Should return the suffix and extension of this export file (like "_flame.stabilizer")
|
4
|
+
def self.desc_and_extension
|
5
|
+
"pftrack.2dt"
|
6
|
+
end
|
7
|
+
|
8
|
+
def start_tracker_segment(tracker_name)
|
9
|
+
# If there was a previous tracker, write it out
|
10
|
+
# - now we know how many keyframes it has
|
11
|
+
if @prev_tracker && @prev_tracker.any?
|
12
|
+
block = [
|
13
|
+
"\n",
|
14
|
+
@tracker_name.inspect, # "autoquotes"
|
15
|
+
@prev_tracker.length,
|
16
|
+
@prev_tracker.join("\n")
|
17
|
+
]
|
18
|
+
@io.puts block.join("\n")
|
19
|
+
end
|
20
|
+
|
21
|
+
# Setup for the next tracker
|
22
|
+
@prev_tracker = []
|
23
|
+
@tracker_name = tracker_name
|
24
|
+
end
|
25
|
+
|
26
|
+
def export_point(frame, abs_float_x, abs_float_y, float_residual)
|
27
|
+
line = "%s %.3f %.3f %.3f" % [frame, abs_float_x, abs_float_y, float_residual]
|
28
|
+
@prev_tracker << line
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Tracksperanto::Export::ShakeText < Tracksperanto::Export::Base
|
2
|
+
PREAMBLE = "TrackName %s\n Frame X Y Correlation\n"
|
3
|
+
POSTAMBLE = "\n"
|
4
|
+
|
5
|
+
# Should return the suffix and extension of this export file (like "_flame.stabilizer")
|
6
|
+
def self.desc_and_extension
|
7
|
+
"shake_trackers.txt"
|
8
|
+
end
|
9
|
+
|
10
|
+
def start_tracker_segment(tracker_name)
|
11
|
+
if @any_tracks
|
12
|
+
@io.puts POSTAMBLE
|
13
|
+
else
|
14
|
+
@any_tracks = true
|
15
|
+
end
|
16
|
+
|
17
|
+
@io.puts PREAMBLE % tracker_name
|
18
|
+
end
|
19
|
+
|
20
|
+
def end_export
|
21
|
+
@io << "\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
def export_point(frame, abs_float_x, abs_float_y, float_residual)
|
25
|
+
# Shake starts from frame 1, not 0
|
26
|
+
line = " %.2f %.3f %.3f %.3f" % [frame + 1, abs_float_x, abs_float_y, 1 - float_residual]
|
27
|
+
@io.puts line
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Tracksperanto::Export::SynthEyes < Tracksperanto::Export::Base
|
2
|
+
|
3
|
+
# Should return the suffix and extension of this export file (like "_flame.stabilizer")
|
4
|
+
def self.desc_and_extension
|
5
|
+
"syntheyes_2dt.txt"
|
6
|
+
end
|
7
|
+
|
8
|
+
def start_export( img_width, img_height)
|
9
|
+
@width, @height = img_width, img_height
|
10
|
+
end
|
11
|
+
|
12
|
+
def start_tracker_segment(tracker_name)
|
13
|
+
@tracker_name = tracker_name
|
14
|
+
end
|
15
|
+
|
16
|
+
def export_point(frame, abs_float_x, abs_float_y, float_residual)
|
17
|
+
values = [@tracker_name, frame] + syntheyes_coords(abs_float_x, abs_float_y)
|
18
|
+
@io.puts("%s %d %.6f %.6f 30" % values)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# Syntheyes wants very special coordinates, Y down X right,
|
24
|
+
# 0 is center and values are UV float -1 to 1, doubled
|
25
|
+
def syntheyes_coords(abs_x, abs_y)
|
26
|
+
w, h = 2560, 1080
|
27
|
+
x = (abs_x / @width.to_f) - 0.5
|
28
|
+
y = (abs_y / @height.to_f) - 0.5
|
29
|
+
# .2 to -.3, y is reversed and coords are double
|
30
|
+
[x * 2, y * -2]
|
31
|
+
end
|
32
|
+
end
|
data/lib/import/base.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
class Tracksperanto::Import::Base
|
4
|
+
include Tracksperanto::Safety
|
5
|
+
|
6
|
+
# The original width of the tracked image
|
7
|
+
# Some importers need it
|
8
|
+
attr_accessor :width
|
9
|
+
|
10
|
+
# The original height of the original image.
|
11
|
+
# Some importers need it
|
12
|
+
attr_accessor :height
|
13
|
+
safe_reader :width, :height
|
14
|
+
|
15
|
+
def self.inherited(by)
|
16
|
+
Tracksperanto.importers << by
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
# Should return an array of Tracksperanto::Tracker objects
|
21
|
+
def parse(track_file_content)
|
22
|
+
[]
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
class Tracksperanto::Import::FlameStabilizer < Tracksperanto::Import::Base
|
4
|
+
# Flame records channels in it's .stabilizer file. Per tracker, we use tracker1/track/x and tracker1/track/y as the base
|
5
|
+
# tracking value. Then, the tracker1/shift/x and tracker1/shift/y are added to it. The problem is that when we track backwards
|
6
|
+
# the main reference keyframe for the x and y coordinates that sets the base for the animation might be at the last frame, at
|
7
|
+
# a frame in the middle or in the end of the setup. We have to pluck it out and then we compute the shift relative to the values
|
8
|
+
# in this main frame. Obviously we discard the track width and search width information as we cannot use it in any meaningful way.
|
9
|
+
#
|
10
|
+
# Here is how the relevant portions look like this (note the tab indents, not spaces, indentation starts at hashmark)
|
11
|
+
#Channel tracker1/shift/x
|
12
|
+
# Extrapolation linear
|
13
|
+
# Value 0
|
14
|
+
# Size 185
|
15
|
+
# KeyVersion 1
|
16
|
+
# Key 0
|
17
|
+
# Frame 1
|
18
|
+
# Value 0
|
19
|
+
# Interpolation linear
|
20
|
+
# RightSlope 0.15802
|
21
|
+
# LeftSlope 0.15802
|
22
|
+
# End
|
23
|
+
# Key 1
|
24
|
+
#
|
25
|
+
# This is in big lines:
|
26
|
+
# (tabs)Key(space)Value
|
27
|
+
def parse(stabilizer_setup_content)
|
28
|
+
trackers = []
|
29
|
+
|
30
|
+
io = StringIO.new(stabilizer_setup_content)
|
31
|
+
|
32
|
+
trackers
|
33
|
+
end
|
34
|
+
end
|