2016-11-10 2 views
0

Я разрабатываю приложение iOS на базе ГИС, использующее Swift 3.0. Я хочу нарисовать плитки на карте, а изображения плиток хранятся в базе данных SQLite.Как нарисовать плитки на карте из базы данных?

Мой вопрос в том, как я могу получить изображение плитки из базы данных и нарисовать изображение теса на карте, поскольку в базе данных отображаются значения масштаба (значения будут 12, 13 и т. Д.), Tile_row (значения будут 4122, 3413 и т. Д.).), tile_column (значения будут 4122, 3413 и т. д.) и данные, но я получаю значение уровня масштабирования в тысячах, и я получаю значения широты и долготы в приложении iOS, поэтому мне нужно преобразовать эти значения в соответствие значениям в базе данных. Я нашел способ преобразования уровня масштабирования в масштабе от 1 до 18, но я не знаю, могу ли я сопоставить значение tile_row и tile_column с использованием широты и долготы.

Также проверьте, пожалуйста, что мой код, который преобразует уровень масштабирования 1 до 18 (по аналогии с Google уровня масштабирования карты) является правильным:

let zoomLevel = Int(log2(360/MKCoordinateRegionForMapRect(mapRect).span.longitudeDelta)) 

Спасибо.

ответ

2

В IOS (и большинстве картографических систем) изображения черепицы хранятся в структуре каталогов, где каждый уровень масштабирования является родительским каталогом с номером уровня масштабирования. В этом каталоге есть один или несколько каталогов, названных с номерами продольной черепицы плиток ниже - например, при уровне масштабирования 10 на 1024 плитки, а ваши каталоги могут быть 750, 751, 752 и 753, если это их изображения упал относительно. Под каждой координатой долготы (x-координата) находятся изображения (256 × 256 пикселей) для этой координаты y, каждая из которых обозначена для координаты x-плитки, опять же из 1024 при уровне масштабирования 10.

Чтобы найти, где вы находитесь в этих диапазонах используйте MKMapPointForCoordinate (CLLocationCoordinate2D), который даст вам точки карты lat (y) и lon (x) местоположения при полном уменьшении. Чтобы использовать номер долготы (у) плитки:

Int((pow(2.0, Double(z)) as Double) * point.y/268435456.0) 

... где большое число является общим количеством точек на оси х при уровне масштабирования 0 (2^20 плитки * 256 пикселей/плитка). Таким образом, если point.x составляет 1/3 от большого числа, изображение равно 1/3 пути до 1024, а целое число, представляющее интервал в 256 пикселей (т. Е. Плитку), в которое попадает число, - это имя каталога.

Аналогично вычисляются точка и точка плитки широты (y), и это число является именем файла изображения. Так, при уровне масштабирования 10 изображения для плитки 752 из 1024 по оси х и 486 из 1024 по оси у будет в файле:

...Documents/Maps/yourDirectory/10/752/486.png 

... при условии, что вы называете ваш общий каталог карты Карты и конкретный каталог для этого набора плиток yourDirectory. Когда вы используете оверлей, вы должны использовать эту информацию в каталоге вместе с остальной частью установки, чтобы создать экземпляр объекта MKTileOverlay. Обратите внимание, что смещения находятся из нижнего левого угла, если вы не указали, что они меняются на противоположные, так как они думают о осях x и y (напоминают вам об использовании CoreGraphics для UIImage?).

Наконец, вот как рассчитать уровень масштабирования заданного два угловых точек области, что я хочу, чтобы захватить снимок для:

let position1 = MKMapPointForCoordinate(bottomRight) 
    let position2 = MKMapPointForCoordinate(topLeft) 
    let xPosition1 = position1.x/Setting.shared.mapScale 
    let xPosition2 = position2.x/Setting.shared.mapScale 
    let yPosition1 = position1.y/Setting.shared.mapScale 
    let yPosition2 = position2.y/Setting.shared.mapScale 

    let relativeSpanX = xPosition1 - xPosition2 // X distance between points relative to size of full map 
    let relativeSpanY = yPosition1 - yPosition2 // Y distance between points relative to size of full map 
    let spanForZoom = max(relativeSpanX, relativeSpanY) 

    startingZoom = max(10, Int(log2(1.0/spanForZoom)) - 1) 

, которая получает вас уровень масштабирования для плитки, которая подходит размер область, которая включает обе точки, но обратите внимание, что ни одна стандартная плитка такого размера (или любого размера, меньшего полной карты) может включать эти две точки в зависимости от того, где они лежат относительно сетки. Например, если они охватывают первый меридиан, первый шаг на 4 плитки на уровне масштабирования 1 будет их разделять, поэтому вам может понадобиться 2-4 плитки начального размера масштабирования, чтобы получить оба.В идеале напишите функцию, которая сообщит вам номер плитки (x и y), который включает CLLocationCoordinate2D, так как это очень удобно, когда вы выбираете, загружаете и собираете свои плитки.

В то время как вы можете уйти с геометрическим подходом, как вы показываете для вычисления значений продольной/оси Y, MKMapPointForCoordinate() незаменим для расчетов по широте/оси y, поскольку карта мерцатора является нелинейной по мере движения север или юг, и функция позаботится об этом для вас.

Это должно начаться, но это придирчивый процесс - одна вещь, на которую нужно сосредоточиться, состоит в том, что макет всегда находится слева внизу; вы легко можете запутаться, когда вы соберете и отметьте плитки.

Я использую следующую функцию для вычисления координаты х и у для плитки, что точка находится в течение заданного масштаба:

func getTileCoordinates(location: CLLocationCoordinate2D, z: Int) -> (x: Int, y: Int) 
{ 
    let point = MKMapPointForCoordinate(location) 
    let locationX = Int((pow(2.0, Double(z)) as Double) * point.x/268435456.0) 
    let locationY = Int((pow(2.0, Double(z)) as Double) * point.y/268435456.0) 

    return (locationX, locationY) 
} 

... опять же, где 268435456,0 общее число пикселей на уровне 20 масштабирования вдоль оси x или y. Обратите внимание, что все это для карт Map Map Map и отображает их.

+0

BTW, я добавил max при вычислении масштабирования, так как я не хотел уменьшать масштаб до уровня 10, так как я использую карты для поддержки навигации, и вы не можете позволить себе больше 6 или 7 уровней zoom (в 7 вам нужно более 5000 плиток!). Минус 1 состоит в том, чтобы получить небольшое пространство для дыхания и увеличить вероятность того, что я получу обе точки на 1 или 2 плитки. –

+0

Спасибо за ваш ответ. Можете ли вы объяснить переменные или как получить эту переменную, которую вы используете, например, z, point, mapScale. Вы добавили код, чтобы получить уровень масштабирования, но я не уверен, что такое мой уровень масштабирования, spanForZoom - мой уровень масштабирования? – Hardik

+0

bottomRight и topLeft находятся в углах области, для которой я хочу карту. Я получаю их, находя максимальные и минимальные широты и долготы среди мест в моих путевых точках и используя их для определения двух точек: bottomRight = (min, max) и topLeft = (max, min). Оттуда расчет startZoom должен сделать все остальное, чтобы получить зум. Значения .x и .y в этих вычислениях являются свойствами значений MKMapPoints, возвращаемых системой, соответствующей точкам x и y на графике. [см. следующий комментарий] –