2016-11-10 1 views
0

Je développe une application iOS basée sur GIS en utilisant Swift 3.0. Je veux dessiner des mosaïques sur la carte et les images de mosaïques sont stockées dans la base de données SQLite. Ma question est de savoir comment récupérer l'image de la base de données et dessiner cette image sur la carte, car la base de données contient des colonnes zoom (les valeurs seront 12, 13, etc.), tile_row (les valeurs seront 4122, 3413, etc. tile_column (les valeurs seront 4122, 3413, etc.) et les données mais j'obtiens une valeur de niveau de zoom en milliers et j'obtiens des valeurs de latitude et de longitude dans l'application iOS, donc je dois convertir ces valeurs pour correspondre aux valeurs dans la base de données. J'ai trouvé un moyen de convertir le niveau de zoom en échelle de 1 à 18, mais je ne sais pas si je peux faire correspondre les valeurs tile_row et tile_column en utilisant la latitude et la longitude.Comment dessiner des tuiles sur la carte de la base de données?

s'il vous plaît vérifier aussi que mon code qui convertissent le niveau de zoom à 1 à 18 (similaire à la carte google niveau de zoom) est correct:

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

Merci.

Répondre

2

Dans IOS (et la plupart des systèmes de mappage), les images de tuiles sont stockées dans une structure de répertoires où chaque niveau de zoom est un répertoire parent nommé avec le numéro de niveau de zoom. Sous ce répertoire, il y a un ou plusieurs répertoires avec les numéros de pavés longitudinaux des pavés ci-dessous - par exemple, au niveau de zoom 10, il y a 1024 carreaux et 750, 751, 752 et 753 si leurs images tombé relativement. Sous chaque répertoire de longitude (coordonnées x) sont les images (256 x 256 pixels) pour cette coordonnée y, chacune nommée pour la coordonnée x carrelage, encore une fois sur 1024 au niveau de zoom 10.

Pour trouver où vous êtes dans ces plages, utilisez MKMapPointForCoordinate (CLLocationCoordinate2D), qui vous donnera les points de carte lat (y) et lon (x) d'un emplacement en mode de zoom arrière. Pour obtenir la longitude (y) l'utilisation du numéro de tuile:

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

... où le grand nombre est le nombre total de points sur l'axe des x au niveau de zoom 0 (2^20 tuiles * 256 pixels/tuile). De cette façon, si le point.x est 1/3 du grand nombre, l'image est la tuile 1/3 du chemin à travers 1024, et l'entier représentant l'intervalle de 256 pixels (c.-à-d. du répertoire.

Le point de la carte de latitude (y) et le numéro de la vignette sont calculés de la même manière, et ce nombre correspond au nom du fichier image. Ainsi, au niveau de zoom 10 sur l'image pour la tuile 752 sur 1024 le long de l'axe des x et 486 sur 1024 le long de l'axe y serait dans le fichier:

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

... vous votre fournie Nom répertoire global de la carte Maps et le répertoire spécifique pour cet ensemble de tuiles yourDirectory. Lorsque vous utilisez la superposition, vous utiliserez ces informations de répertoire avec le reste de l'installation pour instancier un objet MKTileOverlay. Notez que les décalages sont dans le coin inférieur gauche sauf si vous spécifiez qu'ils sont inversés car ils pensent à des axes x et y (vous rappelant utiliser CoreGraphics pour un UIImage?).

Enfin, voici comment je calcule le niveau de zoom donné deux points d'angle d'une région que je veux capturer un instantané pour:

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) 

qui vous obtient le niveau de zoom pour une tuile qui correspond à la taille la zone qui comprend les deux points, mais notez qu'aucune case standard de cette taille (ou aucune taille inférieure à la carte complète) ne peut inclure ces deux points en fonction de leur position par rapport à la grille. Par exemple, s'ils s'étendent sur le premier méridien, la première étape à 4 tuiles au niveau de zoom 1 les séparera, vous aurez donc besoin de 2 - 4 tuiles de la taille de zoom de départ pour obtenir les deux.Idéalement, écrivez une fonction qui vous indique le nombre de tuiles (x et y) qui inclut un CLLocationCoordinate2D puisque cela devient très pratique lorsque vous choisissez, téléchargez et récupérez vos tuiles. MKMapPointForCoordinate() est indispensable pour les calculs de latitude/axe des Y, car la carte de mercator est non linéaire lorsque vous déplacez Nord ou Sud, et la fonction prend soin de cela pour vous.

Cela devrait vous aider à démarrer, mais c'est un processus difficile - une chose à se concentrer est le fait que la mise en page est toujours à partir de la partie inférieure gauche; Il est facile de se perdre lorsque vous rassemblez et étiquetez les carreaux.

utiliser la fonction suivante pour calculer les coordonnées x et y pour la tuile qui est un point à un niveau de zoom suivant:

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) 
} 

... encore une fois, où 268435456,0 est le nombre total de pixels dans le niveau de zoom 20 carte le long de l'axe x ou y. Notez, tout cela est pour les cartes MapKit Apples et les fonctions pour les afficher.

+0

BTW, j'ai ajouté le maximum sur le calcul de zoom puisque je ne voulais pas faire un zoom arrière plus loin que le niveau 10, car j'utilise les cartes pour soutenir la navigation et vous ne pouvez pas payer plus de 6 ou 7 niveaux de zoom (à 7 vous avez besoin de plus de 5 000 tuiles!). Le moins 1 est d'avoir un peu d'espace de respiration et d'augmenter les chances que je puisse obtenir les deux points sur 1 ou 2 tuiles. –

+0

Merci pour votre réponse. Pouvez-vous s'il vous plaît expliquer les variables ou comment obtenir ces variables que vous utilisez comme z, point, mapScale. Vous avez ajouté du code pour obtenir le niveau de zoom, mais je ne suis pas sûr de mon niveau de zoom, spanForZoom est mon niveau de zoom? – Hardik

+0

bottomRight et topLeft sont aux coins de la zone pour laquelle je veux la carte. Je les obtiens en trouvant les latitudes et longitudes maximales et minimales parmi les emplacements dans mes waypoints et en les utilisant pour définir les deux points: bottomRight = (min, max) et topLeft = (max, min). A partir de là, le calcul de startZoom devrait faire le reste pour obtenir le zoom. Les valeurs .x et .y de ces calculs sont des propriétés des valeurs MKMapPoints renvoyées par le système correspondant aux points x et y d'un graphique. [voir commentaire suivant] –