Pull to refresh
0

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

Reading time 6 min
Views 14K
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, подлец, не видит спутников.
Утешился тем, что появляется (прекрасный?) повод познакомиться с (прекрасной?) спутницей у окна.

У иллюминатора спутники и спутницы видны чудесно.
Tags:
Hubs:
+26
Comments 11
Comments Comments 11

Articles

Information

Website
bashni.org
Registered
Founded
Employees
Unknown
Location
Россия