Class: Graph

Inherits:
Object
  • Object
show all
Defined in:
lib/graph.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(trial, deltas, hfrac, test = false) ⇒ Graph

Returns a new instance of Graph.



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/graph.rb', line 16

def initialize trial,deltas,hfrac,test=false
  #deltas we will compute
  @deltas = deltas
  ilog "Will compute deltas for #{@deltas.inspect}."
  #in case the deltas are to small/big change this factor
  @delta_factor = 256
  #in case the angles are to small/big change this factor
  @euler_factor = hfrac
  #this factor governs how many pixels the points are away from another
  @x_factor = 4
  #get the data from the database
  parser = TrackerDataParser.new trial,test
  @data = parser.data
  #generate unique array with all occuring timestamps and prepare @values
  @timestamps = build_timestamps
  #fill values (deltas,etc.)
  @previous = {:left => NMatrix.float(4,4), :right => NMatrix.float(4,4)}
  fill_values
  #build the points array (this will be used later on to draw the graph)
  @points = build_points
end

Instance Attribute Details

#deltasObject

Returns the value of attribute deltas.



14
15
16
# File 'lib/graph.rb', line 14

def deltas
  @deltas
end

#pointsObject

Returns the value of attribute points.



14
15
16
# File 'lib/graph.rb', line 14

def points
  @points
end

Instance Method Details

#build_pointsObject

build the points array we’ll use later on to draw the graph



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/graph.rb', line 140

def build_points
  @timestamps.each_index do |i|
    ts = @timestamps[i]
    #do the following for both hands
    [:left,:right].each do |h|
      #if tracker data are missing we substitute
      if @values.has_key? ts
        @values[ts][h] = get_missing_values if @values[ts][h].empty?
      end
      #set index and x position
      @values[ts][h][:i] = i
      x = i*@x_factor
      @values[ts][h][:x] = x
      #now we create a Qt::PointF.new(x,y) for each euler angle
      @values[ts][h][:euler].each do |name,a|
        #create Point, mirror hands on x axis and apply y-scaling
        y = 0
        unless @values[ts][h][:blackout]
          y += @euler_factor-a[:value]*@euler_factor/Math::PI 
          y *= -1.0 if h.eql? :left
        end
        #and add the point to the euler values
        @values[ts][h][:euler][name][:point] = Qt::PointF.new(x,y)
      end
      #now we create a Qt::PointF.new(x,y) for every delta type
      @values[ts][h][:deltas].each do |type,delta|
        #create Point, mirror hands on x axis and apply y-scaling
        y = delta[:value]*@delta_factor
        y *= -1.0 if h.eql? :left
        #and add the point to the delta values
        @values[ts][h][:deltas][type][:point] = Qt::PointF.new(x,y)
      end
    end  
  end
  dlog "Processed #{@values.length} timestamps."   
  points = @values.sort
  dlog "points array has #{points.length} entries."
  return points
end

#build_timestampsObject

build an array with all occuring timestamps



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/graph.rb', line 39

def build_timestamps
  @values = {}
  tss = []
  @data[:reference].each { |t,v| tss << t }
  @data[:left].each { |t,v| tss << t }
  @data[:right].each { |t,v| tss << t }
  dlog "tss count: #{tss.length}"
  timestamps = (tss.uniq).sort
  dlog "Unique timestamps: #{timestamps.length}"
  dlog "Unique timestamps first: #{timestamps.first}"
  #now preparing @values
  timestamps.each do |t|
    @values[t] = {:left => {}, :right => {}}
  end
  return timestamps
end

#compute_deltas(hand, values, t = 0) ⇒ Object

compute deltas for plotting



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/graph.rb', line 99

def compute_deltas hand,values,t=0
  #we'll put the deltas in here
  ds = {}
  #get the matrix
  m = values[:relative]
  #to reduce computation time we only compute what's needed
  if @deltas.include? :simple
    #compute simple delta over the complete 4x4 matrix
    value = (m-@previous[hand]).abs.sum
    ds[:simple] = { :value => value }
  end
  if @deltas.include? :pos
    #compute simple delta over the position vector
    value = (m[3,0..2]-@previous[hand][3,0..2]).abs.sum
    ds[:pos] = { :value => value }
  end
  if @deltas.include? :rot
    #compute simple delta over the 3x3 rotation matrix
    value = (m[0..2,0..2]-@previous[hand][0..2,0..2]).abs.sum
    ds[:rot] = { :value => value }  
  end
  if @deltas.include? :xrot
    #compute simple delta over the x-rotation axis vector
    value = (m[0,0..2]-@previous[hand][0,0..2]).abs.sum
    ds[:xrot] = { :value => value }  
  end
  if @deltas.include? :yrot
    #compute simple delta over the y-rotation axis vector
    value = (m[1,0..2]-@previous[hand][1,0..2]).abs.sum
    ds[:yrot] = { :value => value }
  end
  if @deltas.include? :zrot
    #compute simple delta over the z-rotation axis vector
    value = (m[2,0..2]-@previous[hand][2,0..2]).abs.sum
    ds[:zrot] = { :value => value } 
  end     
  #and return the computed deltas
  return ds
end

#compute_euler_angles(values) ⇒ Object

compute euler angles for plotting en.wikipedia.org/wiki/Euler_angles



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/graph.rb', line 82

def compute_euler_angles values
  #we'll put the angles in here
  e = {}
  #get the hand matrix
  m = values[:relative]
  #alpha = atan2(-Z2, Z1)
  e[:alpha] = { :value => Math.atan2(-1.0*m[2,1],m[2,0]) }
  #beta = atan2(Z3, sqrt(Z1^2+Z2^2))
  e[:beta] = { :value => Math.atan2(m[2,2],Math.sqrt(m[2,0]**2+m[2,1]**2)) }
  #gamma = -atan2(Y3,-X3) if Z3 < 0
  e[:gamma] = { :value => -1.0*Math.atan2(m[1,2],-1.0*m[0,2]) } if m[2,2] <= 0.0
  #gamma = atan2(Y3,X3) if Z3 > 0
  e[:gamma] = { :value => Math.atan2(m[1,2],m[0,2]) } if m[2,2] > 0.0
  return e
end

#fill_valuesObject

fill values with parsed data



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/graph.rb', line 57

def fill_values
  [:left,:right].each do |hand|
    dlog "Data for #{hand.inspect} has #{@data[hand].length} entries."
    #it's crucial to do sort here, otherwise the timestamps are mixed up
    @data[hand].sort.each do |t,v|
      wlog "Empty or nil value hash!" if v.nil? or v.empty?
      #we have tracker data
      v[:blackout] = false
      #will only happen the first time
      @previous[hand] = v[:relative] if @previous[hand].abs.sum == 0.0
      #compute euler angles
      v[:euler] = compute_euler_angles(v)
      #compute deltas for plotting
      v[:deltas] = compute_deltas(hand,v)
      #for next delta computation
      @previous[hand] = v[:relative]
      #put values into @values
      @values[t][hand] = v
    end
  end
  dlog "Processed #{@values.length} values."
end

#get_missing_valuesObject

in case values are missing for timestamps (no tracker data), we’ll supply values



181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/graph.rb', line 181

def get_missing_values
  #we'll put the deltas in here
  missing_deltas = {}
  #put 0.0 to deltas
  @deltas.each { |d| missing_deltas[d] = { :value => 0.0 } }
  #we'll put the euler angles in here
  missing_euler = {}
  #put 0.0 to euler angles
  [:alpha,:beta,:gamma].each { |a| missing_euler[a] = { :value => 0.0 } }
  #and build the values array
  v = { :deltas => missing_deltas, :euler => missing_euler, :blackout => true }
  return v
end