Под крылом самолета о чем-то поет

в 11:28, , рубрики: mobile development, Блог компании Papa Buba Diop, высотомер, график набора высоты, летчик, разработка под iOS, эндокринолог, метки: , , ,

image

Если внимательно посмотреть на крайнее изображение, то легко определить местоположение автора.
Достаточно взять циркуль и атлас России.
Ножку циркуля устанавливаете в Сасово и проводите окружность радиусом 103 км.
Затем строите вторую окружность (с центром в Сормово) радиусом 141 км.
В точке пересечения буду я. Ахтунг! Файер!

Расскажу, как я написал приложение-высотомер, интересное для авиапутешественников. Никакой рекламы. Никаких денег. Чистый код.

Беспечный ездок часто летает Москва-Женева-Москва

Он попросил меня сделать приложение под iPhone, которое показывает текущую высоту над уровнем моря и еще, что-нибудь познавательное.
При этом я помнил, что в самолете, как в сибирской деревне, интернет отсутствует. Я решил впихнуть в приложение список всех зарегистрированных аэропортов мира и салонов женского белья. Чем еще заняться на борту аэроплана, как не созерцанием картинок?

Включение GPS

GPS-датчик Вашего iPhone хранит не только планетарные координаты, но и высоту над уровнем моря. Её б взглянуть (оцените фонетику). Точность высотомера зависит от многих факторов, но иногда вполне хороша — менее 6 метров. В этом случае можно, включив приложение, прыгнуть с крыши небоскреба и наблюдать онлайн изменение высоты. ⚠️Предупреждение! Это может быть опасно для Вашего здоровья⚠️.

Включение GPS-трекера в приложении занимает 7 строк

    CLLocationManager *locationManager; // это в заголовке класса типа ViewController
   // Do any additional setup after loading the view, typically from a nib.
    locationManager = [CLLocationManager new];
    [locationManager requestWhenInUseAuthorization];
    [locationManager requestAlwaysAuthorization];
    locationManager.delegate = self;
    locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    [locationManager startUpdatingLocation];

После этого в Вашем классе появляется две функции, в которые регулярно сваливаются сообщения от GPS-датчика.
Одна функция оживает, когда датчик работает, а вторая — когда датчик сломался или не видит спутников.


- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
    CLLocation *currentLocation = [locations objectAtIndex:0];
    NSLog(@"GPS Tracking   %f", currentLocation.verticalAccuracy);
    [playView updateHeight:currentLocation.altitude]; // это личное
 }

-(void) locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    NSLog(@"GPS Error   %@, denied=%d", error.description, error.code==kCLErrorDenied);
}

Думаете, сейчас все заработает? Не-а

Для работы приложения вышесказанного оказалось недостаточно. В функцию didUpdateLocations ничего не приходило. И, вообще, она не вызывалась. И функция didFailWithError не дышала.
Оказалось в настройках приложения надо включить две галочки, (следим за рукой, рраз) — Targets-> Capabilities-> Background modes->
image
После этих магических действий приложение заработало, йо-хо-хо!
Как Вы будете теперь обрабатывать сообщения — дело сугубо индивидуальное.

Дизайн приложения

Я решил в режиме портрета показывать

  • Большими цифрами высоту;
  • Маленькими цифрами — точность измерений;
  • Красивым синим графиком — ежесекундный трекинг высоты;
  • Очень красивым бордовым графиком — ежеминутный трекинг высоты.

Ну да, бордовая точка добавляется к графику 1 раз в минуту. Всего таких точек 25 штук, поэтому старые точки при появлении новых забываются и не рисуются. Все просто? Да, и живенько так.

Разумеется, в режиме пейзажа большие цифры красиво уходят и появляется график всего сеанса.
Добавил кнопки остановить трекинг и продолжить или начать слежку заново.
Эти кнопки необходимы, поскольку режим слежки поедает батарейку (я, правда, этого не заметил) и зажигает неприятный синий фон в верхней части экрана, когда приложение уходит в спящий или неактивный режим.

Красивые графики

Для рисования графиков я применил следующий трюк.
Завел картинки
image

Обозвал отрезки между точками графика типом UIImageView
И трансформировал отрезки согласно закону линейной алгебры, да святится имя ее


    for (int k=0;k<24-1;k++) {
        UIImageView *p1 = [pointsQ objectAtIndex:k];
        UIImageView *p2 = [pointsQ objectAtIndex:k+1];
        UIImageView *p = [linesQ objectAtIndex:k];
        
        float x1 = p1.center.x;
        float x2 = p2.center.x;
        float y1 = Y0 - (q2[k]-hmin)*dh;
        float y2 = Y0 - (q2[k+1]-hmin)*dh;
        float l2 = hypot((x2-x1),(y2-y1));
        float cDy = 1.0/l2;
        float a = -(x2-x1)*2.0/cellDy;
        float c = -(y2-y1)*cDy;
        float b = -(y2-y1)*2.0/cellDy;
        float d = (x2-x1)*cDy;
        float tx = 0.0;
        float ty = 0.0;
        
        p.alpha =  (q1[k]*q1[k+1]) ? 1.0 : 0.0;
        p.center = CGPointMake(0.5*(x1+x2), 0.5*(y1+y2));
        p.transform = CGAffineTransformMake(a, b, c, d, tx, ty);
    }

Здесь p1, p2 — точки, между которыми надо провести отрезок p, q1[x] — массив флагов значения высоты (0-нет значения), q2[x] — массив значений высоты, cellDy — размер картинки в пикселях.Y0 — сдвиг графика по высоте. Извращенец, скажете? Да, люблю такие фокусы, что уж там скрывать, помню времена игр разума.
Последние три оператора можно заменить на один, но это домашнее задание.

Ответ на домашнее задание

        p.transform =  (q1[k]*q1[k+1]) ? CGAffineTransformMake(a, b, c, d, 0.5*(x1+x2), 0.5*(y1+y2)) : CGAffineTransformMakeScale(0, 0);

image
Вот такой полет. При большом количестве данных интерполирую значения высот на 40 ключевых точек. Проверял работу 36 часов подряд, думаю никто мой рекорд не переплюнет.

Список аэропортов

Список аэропортов надо поместить в приложение, чтобы он был доступен в любой момент, независимо от наличия интернета.
Забрал данные об аэродромах по первой ссылке от запроса free airports list xml
Упаковал список в airports.sql файл (менее 9000 единиц), файл добавил в проект, при запуске приложения читаю и загружаю airports.sql в структуру Airport

#import <sqlite3.h>
#import <Foundation/Foundation.h>

@interface Airport : NSObject
{
}

@property (nonatomic) NSInteger db_id;
@property (nonatomic) NSString *name;
@property (nonatomic) NSString *city;
@property (nonatomic) NSString *country;
@property (nonatomic) NSString *iata;
@property (nonatomic) NSString *icao;


@property (nonatomic) double latitude;
@property (nonatomic) double longitude;
@property (nonatomic) double altitude;

@property (nonatomic) int timezone;

@property (nonatomic) NSString *dst;
@property (nonatomic) NSString *timezone_name;
@property (nonatomic, retain) CLLocation* location;
@property (nonatomic,readonly) double distanceFromHere;


- (id) initWithSQLStatement:(sqlite3_stmt *) selectstmt;

- (double) distanceFromLocation:(CLLocation*)location;
/*
id integer, 
 name text, 
 city text, 
 country text, 
 iata text, 
 icao text, 
 latitude float, 
 longitude float, 
 altitude float, 
 timezone integer, 
 dst text, 
 timezone_name text
*/  это структура базы данных, если чо забыл

@end

Вычисление расстояния от текущей позиции до любого аэропорта сделано Apple-ом задолго до меня


- (double) distanceFromLocation:(CLLocation*)location
{
    _distanceFromHere = [self.location distanceFromLocation:location];
    return _distanceFromHere;
}

Затем добавляю сортировку и вывожу списком десятку ближайших аэропортов (UITableViewController).
С удивлением обнаружил, что ближайший аэродром находится не в Нижнем Новгороде, а в Сасово Рязанской губернии. Вот чудеса. Я же был в этом Сасово в лётном училище в 1991 году. Мы с Николя Д. сделали симулятор ЯК-52 на AT-286. 12 кадров в секунду, ассемблер, помню смутно, Паскаль, снова ассемблер, коктейль Шасси-Рояль.

Список салонов женского белья

Изначально хотел засунуть фотографии и фейковые имена виртуальных куртизанок крупнейших городов Европы. Летишь, понимаешь, а список обновляется. Но не рискнул — вдруг Review Team умеет подменять высоту, забанят меня за голые сиськи. Ограничился красивым бельем.
image
Добавил по тому же алгоритму, что и аэродромы.
Однако, получился квест, фишка работает только на высоте выше 9000 метров.

Бодание с магазином

image

Приложение было быстро сделано (в рамках бесполезного мероприятия 6 приложений за 6 недель) и долго одобрялось в магазине. Очень долго, почти два месяца.
Засада была в том, что пользователя надо предупреждать следующей фразой

Continued use of GPS running in the background can dramatically decrease battery life

Первый раз приложение тормознули — сказали давай исправляй.

Я красиво вставил

⚠️Continued use of GPS running in the background can dramatically decrease battery life⚠️

И оказался идиотом. Эти желтые спец-символы запрещены.
Пришлось ждать еще 10 дней, а потом еще 10…
И вот сегодня одобрили.

Проверка приложения

Да, пришлось лететь. Не мне, разумеется, овес нынче дорог. Выяснилась проблема. В креслах у прохода приложение частенько не работает. GPS, подлец, не видит спутников.
Утешился тем, что появляется (прекрасный?) повод познакомиться с (прекрасной?) спутницей у окна.

У иллюминатора спутники и спутницы видны чудесно.

Автор: PapaBubaDiop

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js