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

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. ++


432
433
434
435
436
437
438
439
440
441
442
443
444
# File 'lib/kamelopard/helpers.rb', line 432

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


416
417
418
419
420
# File 'lib/kamelopard/helpers.rb', line 416

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


377
378
379
# File 'lib/kamelopard/helpers.rb', line 377

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


381
382
383
# File 'lib/kamelopard/helpers.rb', line 381

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


369
370
371
372
373
374
375
# File 'lib/kamelopard/helpers.rb', line 369

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 / Math::PI
    h = h + 180.0 if y2 < y1
    h
end

.get_roll(p) ⇒ Object


396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
# File 'lib/kamelopard/helpers.rb', line 396

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 / Math::PI

    @@options[:exaggerate] * (angle - 180)
end

.get_tilt(p) ⇒ Object


385
386
387
388
389
390
391
392
393
394
# File 'lib/kamelopard/helpers.rb', line 385

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 / Math::PI / @@options[:exaggerate]
            # the / 2.0 is just because it looked nicer that way
    90.0 + t
end

.normalize_points(p) ⇒ Object


450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
# File 'lib/kamelopard/helpers.rb', line 450

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


446
447
448
# File 'lib/kamelopard/helpers.rb', line 446

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