PowerAR — объединяем PowerBI и ARKit на поверхности стола
Привет, Хабр! Помните недавнюю конференцию Apple, на которой был представлен ARKit? Ой, стоп-стоп, это же блог Microsoft. Хотя, почему бы и нет. Ведь наши партнеры решили поэкспериментировать и совместить новый фреймворк от Apple с возможностями сервиса PowerBi от Microsoft. Подробнее под катом!
Передаю слово автору
В частности, на создание подобного приложения вдохновил концепт от Meta.
Старт проекта
Создавать проект было решено на Swift 4. Часть наших клиентов используют для передачи данных в PowerBI формат CSV, который мы и решили брать как основу для вытягивания данных в реальный мир.
Пример данных для визуализации лидов:
Media,Июнь,Июль,Август,Всего
Yandex/CPC,82,70,20,172
Google/CPC,73,50,33,156
Yandex/Organic,67,45,28,140
Google/Organic,85,65,17,167
Youtube,54,42,24,120
Vk.com,33,58,20,111
Раз в сутки из Google Analytics и/или Я.Метрики по API выгружаются данные, собираются в CSV-файл и становятся доступы для выгрузки нашим приложением по ключу. Приложение обращается к серверу, выгружает обновленный файл, считывает его содержимое и синхронизирует данные из него с уже накопленными в смартфоне. Первоначальная загрузка приложения вытягивает все CSV-отчеты за последние 30 дней.
func generateNumbers(fromDataWithIndex index: Int) -> [[Double]]? {
let resourceName = String(format: "PowerBI_CSV", index)
guard let dataPath = Bundle.main.path(forResource: resourceName, ofType: "csv") else {
print(String(format: "Could Not Load Data %@", resourceName))
return nil
}
var data = [[Double]]()
if let dataString = try? String(contentsOfFile: dataPath) {
let lines = dataString.components(separatedBy: "\n")
let headerEntries = lines[0].components(separatedBy: ",")
for line in lines[1...] {
let lineEntries = line.components(separatedBy: ",")
if lineEntries.count == headerEntries.count {
data.append(lineEntries[1...].map({ Double($0) ?? 0.0 }))
}
}
}
return data
}
Далее в дело вступает ARKit. Запуск приложения сопровождается стартом сессии объекта ARSession, а затем генерирует 3D-модели столбцов, рассчитывая их высоту, исходя из данных CSV-файла.
var session: ARSession {
return sceneView.session
}
override func viewDidLoad() {
super.viewDidLoad()
sceneView.delegate = self
sceneView.scene = SCNScene()
sceneView.showsStatistics = false
sceneView.antialiasingMode = .multisampling4X
sceneView.automaticallyUpdatesLighting = false
sceneView.contentScaleFactor = 1.0
sceneView.preferredFramesPerSecond = 60
DispatchQueue.main.async {
self.screenCenter = self.sceneView.bounds.mid
}
if let camera = sceneView.pointOfView?.camera {
camera.wantsHDR = true
camera.wantsExposureAdaptation = true
camera.exposureOffset = -1
camera.minimumExposure = -1
}
}
ARKit, используя компьютерное зрение, определяет поверхность и, в случае обнаружения плоскости, позволяет разместить собранные компанией данные в виде 3D-столбцов.
Сложности, которые возникли, и решения, которые нашлись
Во-первых, определение плоскостей. Сейчас все ещё сохраняется большой процент вероятности, что поверхность не распознается. Здесь остается лишь дождаться повышения точности работы самого ARKit и посоветовать использовать в подобных приложениях анимацию в случае успешного распознавания поверхности стола. Создать такой индикатор успешного распознавания можно следующим образом:
/*
s1 s2
_ _
s3 | | s4
s5 | | s6
- -
s7 s8
*/
let sl: Float = 0.5
let st = focusSquareThickness
let c: Float = focusSquareThickness / 2
let s1 = FocusSquareSegment(name: "s1", width: sl, thickness: st, color: focusSquareColor)
let s2 = FocusSquareSegment(name: "s2", width: sl, thickness: st, color: focusSquareColor)
let s3 = FocusSquareSegment(name: "s3", width: sl, thickness: st, color: focusSquareColor, vertical: true)
let s4 = FocusSquareSegment(name: "s4", width: sl, thickness: st, color: focusSquareColor, vertical: true)
let s5 = FocusSquareSegment(name: "s5", width: sl, thickness: st, color: focusSquareColor, vertical: true)
let s6 = FocusSquareSegment(name: "s6", width: sl, thickness: st, color: focusSquareColor, vertical: true)
let s7 = FocusSquareSegment(name: "s7", width: sl, thickness: st, color: focusSquareColor)
let s8 = FocusSquareSegment(name: "s8", width: sl, thickness: st, color: focusSquareColor)
s1.position += SCNVector3Make(-(sl / 2 - c), -(sl - c), 0)
s2.position += SCNVector3Make(sl / 2 - c, -(sl - c), 0)
s3.position += SCNVector3Make(-sl, -sl / 2, 0)
s4.position += SCNVector3Make(sl, -sl / 2, 0)
s5.position += SCNVector3Make(-sl, sl / 2, 0)
s6.position += SCNVector3Make(sl, sl / 2, 0)
s7.position += SCNVector3Make(-(sl / 2 - c), sl - c, 0)
s8.position += SCNVector3Make(sl / 2 - c, sl - c, 0)
Во-вторых, интерфейс. С приложениями, использующими камеру, важно найти компромисс между количеством элементов на экране и интуитивностью управления. В PowerAR было решено использовать прозрачные кнопки с эффектом размытия и оставить лишь добавление/удаление графиков, а также запуск настроек.
@IBOutlet weak var settingsButton: UIButton!
let blurSettings = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.light))
blurSettings.frame = settingsButton.bounds
blurSettings.isUserInteractionEnabled = false
settingsButton.insertSubview(blurSettings, at: 0)
settingsButton.layer.cornerRadius = 15.0
settingsButton.clipsToBounds = true
И наконец, оптимизация. Даже самое простое приложение c ARKit потребляет 50% CPU iPhone 7, что вызывает его нагрев и повышение скорости разрядки. Команда потратила практически 40% всего времени разработки на то, чтобы максимально оптимизировать использование ресурсов смартфона, особенно на процессоре A9 при использовании 100 отрендеренных столбцов, где изначально на это уходили все доступные приложению ресурсы.
Что получают пользователи
Прежде всего это возможность взглянуть на десятки графиков под любым углом. По сути, перед нами новый вид наглядности. Также подобные графики позволяют делать красивые обложки для ежегодных отчетов инвесторам, совмещая их на фото вместе с документами компании, не прибегая к созданию подобных 3D-макетов в фоторедакторах.
В целом данное приложение пока выступает в качестве концепта, позволяющего пользователям прикоснуться к будущему, в котором дополненная реальность будет все более и более тесно интегрироваться c реальным миром.
Итог
На данный момент приложение уже доступно в качестве демо-версии в App Store и требует установленной iOS 11. В дальнейшем планируется добавление функций подключения внешних источников данных для выгрузки (бета-версия пока имеет предзагруженый набор данных) и расширить перечень видов диаграмм для визуализации. Также заканчиваем тестирование iPad-версии приложения, которая еще сильнее раскроет потенциал просмотра графиков в реальном мире.
Об авторе
Андрей Баранчиков — ведущий разработчик компании A-Teams. C 2010 года занимается разработкой iOS/Android приложений и бэкэнда (Spring/JEE), начинал с разработки серверного ПО для потоковой обработки видео с камер видеонаблюдения. Одним из первых в России выпустил приложения для Apple Watch и Apple TV.
Mixed Reality Imagine Hack
Обратите внимание, что сейчас у нас проходит сбор заявок на международный студенческий конкурс Imagine Cup 2018. Победитель может выиграть 100K $.
В преддверии конкурса мы проводим серию хакатонов, на которых вы можете найти команду или ментора, пообщаться с экспертами и презентовать им свой проект. Ближайший из них будет посвящён разработке под MR/VR и пройдёт 9 — 10 февраля в Москве при поддержке AVRA и ТемоЦентр. Присоединяйтесь.