Module: TelemetryProcessor

Defined in:
lib/kamelopard/helpers.rb

Overview

Given telemetry data, such as from an aircraft, including latitude, longitude, and altitude, this will figure out realistic-looking tilt, heading, and roll values and create a series of FlyTo objects to follow the extrapolated flight path

Constant Summary collapse

Pi =
3.1415926535

Class Method Summary collapse

Class Method Details

.add_flyto(p) ⇒ Object

This is the only function in the module that users are expected to call, and even then users should probably use the tour_from_points function. The p argument contains an ordered array of points, where each point is represented as an array consisting of longitude, latitude, and altitude, in that order. This will add a series of gx:FlyTo objects following the path determined by those points. – XXX Have some way to adjust FlyTo duration based on the distance between points, or based on user input. ++



334
335
336
337
338
339
340
341
342
343
344
345
346
# File 'lib/kamelopard/helpers.rb', line 334

def TelemetryProcessor.add_flyto(p)
    p2 = TelemetryProcessor::normalize_points p
    p = p2
    heading = get_heading p
    tilt = get_tilt p
    # roll = get_roll(last_last_lon, last_last_lat, last_lon, last_lat, lon, lat)
    roll = get_roll p
    #p = Kamelopard::Point.new last_lon, last_lat, last_alt, { :altitudeMode => :absolute }
    point = Kamelopard::Point.new p[1][0], p[1][1], p[1][2], { :altitudeMode => :absolute }
    c = Kamelopard::Camera.new point, { :heading => heading, :tilt => tilt, :roll => roll, :altitudeMode => :absolute }
    f = Kamelopard::FlyTo.new c, { :duration => @@options[:pause], :mode => :smooth }
    f.comment = "#{p[1][0]} #{p[1][1]} #{p[1][2]} to #{p[2][0]} #{p[2][1]} #{p[2][2]}"
end

.fix_coord(a) ⇒ Object



318
319
320
321
322
# File 'lib/kamelopard/helpers.rb', line 318

def TelemetryProcessor.fix_coord(a)
    a = a - 360 if a > 180
    a = a + 360 if a < -180
    a
end

.get_dist2(x1, y1, x2, y2) ⇒ Object



279
280
281
# File 'lib/kamelopard/helpers.rb', line 279

def TelemetryProcessor.get_dist2(x1, y1, x2, y2)
    Math.sqrt( (x2 - x1)**2 + (y2 - y1)**2).abs
end

.get_dist3(x1, y1, z1, x2, y2, z2) ⇒ Object



283
284
285
# File 'lib/kamelopard/helpers.rb', line 283

def TelemetryProcessor.get_dist3(x1, y1, z1, x2, y2, z2)
    Math.sqrt( (x2 - x1)**2 + (y2 - y1)**2 + (z2 - z1)**2 ).abs
end

.get_heading(p) ⇒ Object



271
272
273
274
275
276
277
# File 'lib/kamelopard/helpers.rb', line 271

def TelemetryProcessor.get_heading(p)
    x1, y1, x2, y2 = [ p[1][0], p[1][1], p[2][0], p[2][1] ]
  
    h = Math.atan((x2-x1) / (y2-y1)) * 180 / Pi
    h = h + 180.0 if y2 < y1
    h
end

.get_roll(p) ⇒ Object



298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'lib/kamelopard/helpers.rb', line 298

def TelemetryProcessor.get_roll(p)
    x1, y1, x2, y2, x3, y3 = [ p[0][0], p[0][1], p[1][0], p[1][1], p[2][0], p[2][1] ]
    return 0 if x1.nil? or x2.nil?
  
    # Measure roll based on angle between P1 -> P2 and P2 -> P3. To be really
    # exact I ought to take into account altitude as well, but ... I don't want
    # to
  
    # Set x2, y2 as the origin
    xn1 = x1 - x2
    xn3 = x3 - x2
    yn1 = y1 - y2
    yn3 = y3 - y2
    
    # Use dot product to get the angle between the two segments
    angle = Math.acos( ((xn1 * xn3) + (yn1 * yn3)) / (get_dist2(0, 0, xn1, yn1).abs * get_dist2(0, 0, xn3, yn3).abs) ) * 180 / Pi
  
    @@options[:exaggerate] * (angle - 180)
end

.get_tilt(p) ⇒ Object



287
288
289
290
291
292
293
294
295
296
# File 'lib/kamelopard/helpers.rb', line 287

def TelemetryProcessor.get_tilt(p)
    x1, y1, z1, x2, y2, z2 = [ p[1][0], p[1][1], p[1][2], p[2][0], p[2][1], p[2][2] ]
    smoothing_factor = 10.0
    dist = get_dist3(x1, y1, z1, x2, y2, z2)
    dist = dist + 1
            # + 1 to avoid setting dist to 0, and having div-by-0 errors later
    t = Math.atan((z2 - z1) / dist) * 180 / Pi / @@options[:exaggerate]
            # the / 2.0 is just because it looked nicer that way
    90.0 + t
end

.normalize_points(p) ⇒ Object



352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
# File 'lib/kamelopard/helpers.rb', line 352

def TelemetryProcessor.normalize_points(p)
    # The whole point here is to prevent problems when you cross the poles or the dateline
    # This could have serious problems if points are really far apart, like
    # hundreds of degrees. This seems unlikely.
    lons = ((0..2).collect { |i| p[i][0] })
    lats = ((0..2).collect { |i| p[i][1] })
  
    lon_min, lon_max = lons.minmax
    lat_min, lat_max = lats.minmax
  
    if (lon_max - lon_min).abs > 200 then
        (0..2).each do |i|
            lons[i] += 360.0 if p[i][0] < 0
        end
    end
  
    if (lat_max - lat_min).abs > 200 then
        (0..2).each do |i|
            lats[i] += 360.0 if p[i][1] < 0
        end
    end
  
    return [
        [ lons[0], lats[0], p[0][2] ],
        [ lons[1], lats[1], p[1][2] ],
        [ lons[2], lats[2], p[2][2] ],
    ]
end

.options=(a) ⇒ Object



348
349
350
# File 'lib/kamelopard/helpers.rb', line 348

def TelemetryProcessor.options=(a)
    @@options = a
end