基於隨機定位的地圖資訊獲取方式
基本定義
場景
一個應用要用到地圖,地圖拖動時,要填補新的版圖上的地理資訊
目的
快速獲取螢幕內需要的地圖資訊,不獲取多餘無用的地圖資訊
功能要點
1.確定地圖範圍,獲取的資訊不超出螢幕過多
(比如螢幕地圖查詢100平方米的資訊,服務返回的資訊不能超過130平米的地圖資訊)
2.動態快速獲取資訊,通過定位快速獲取周圍地理資訊,第一時間從快取獲取或者資料庫獲取,且不要有複雜查詢和大量查詢。
絕對定位:座標,傳人任何一個點,都能通過角色定位知道這個點在哪,以及其他延伸計算
通過地圖的中心定位,優先快速確定要獲取那些位置的地理資訊,快速獲取對應的圖塊。
3.根據維度調整資訊獲取範圍和格式
粒度:通過兩個點確定查詢資訊的範圍,同時確定粒度(地圖縮放級別)
(4).原先有的資訊短時間不重複獲取
(拖動地圖導致50%地圖位置換了,還有50%地圖不變,不用再次請求)
確定地圖範圍
通過兩個點,或者中心定位+範圍,要快速得出在範圍內地圖資訊
地圖切割
分塊
將地圖切割均等大小
塊級別
地圖顯示可以是世界地圖,也可以是城鎮地圖,縮放差距很大,地圖塊也要級別表示具體縮放場景
座標
一個絕對座標,作為參考
每一個切割的分塊地圖都有一個座標,座標唯一
確定分塊座標唯一依據:分塊級別,經緯度,
分塊地圖表示方法
獲取範圍內的分塊地圖
矩形對角線兩個點,可以確定範圍
入參:座標1,座標2,粒度(地圖縮放級別)
返回:分塊地圖座標
將問題細分化,可以分解為,先求所有圖塊的x座標,在求x座標,然後陣列相乘,或多所有圖塊的二維座標(x,y)
輸入:點A,點B,地圖擴充套件係數
返回:兩個點覆蓋的範圍
Fun(coordinate c1,coordinate c2,granularity g) return Array(Map-Coordinate)
public static DecimalFormat df = new DecimalFormat("#0.0000");
/**
* -求兩個點包含圖塊座標範圍
* @param x1 點A
* @param x2 點B
* @param granularity 地圖擴充套件係數
* @return A,B兩點包含的圖塊的一維座標
*/
public static double[] range_position(double x1,double x2,double granularity) {
double minX = Math.min(x1, x2);
double maxX = Math.max(x1, x2);
//左邊界
double left = Math.floor(minX/granularity) * granularity;
//右邊界
double right = Math.ceil(maxX/granularity) * granularity;
//相差
double difference = right - left;
double d_pointNumber = difference/granularity;
//一維座標數
int pointNumber = (int) (int)Math.ceil(Double.valueOf(df.format(d_pointNumber)));
double[] points = new double[pointNumber];
points[0] = Double.valueOf(df.format(left + granularity/2));
for(int i = 1; i<pointNumber; i++) {
points[i] = Double.valueOf(df.format(points[i-1] + granularity));
}
return points;
}
呼叫上面方法兩次,分別傳入 x座標 和 y座標,求出(x,y) 集合,得到所有圖塊二維座標。
快速獲取圖塊資訊
地圖資訊要快速獲取,上面返回座標,通過座標和擴充套件級別能確定唯一性,因此可以通過唯一key對應一個圖塊
//圖塊唯一key
//引數 x y 座標 擴充套件係數 圖塊邊長
public static String getMpk(double x,double y, int gly,double mapLength) {
return MapBlock.head + gly + "-"+ df.format(mapLength) + "(" +x + ","+ y + ")";
}
首先應該是初始化的時候,將地圖分塊資訊讀取,放入快取,或者資料庫
如果傳入兩個點,就能獲得對應的圖塊唯一key,直接從快取獲取或者資料庫查詢
code-動態獲取螢幕內地圖
傳入矩形對角線兩個座標,返回矩形內所有圖塊
實現類:
MapRangePosition
package net.narule.algorithm.map;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
/**
* -地圖範圍定位
* @author Narule
*
*/
public class MapRangePosition {
/**
* -給定一個矩形,返回矩形接觸的區域
* @param c1
* @param c2
* @return
*/
public static List<MapBlock> getRangeMapBlock(Coordinate c1,Coordinate c2){
//擴充套件係數
int calculateGly = Granularity.calculateGly(c1, c2);
//圖塊邊長
double mapSideLength = calculateGly * Granularity.unit_length;
double z = c1.getZ();
double[] range_position_x = range_position(c1.getX(),c2.getX(), mapSideLength);
double[] range_position_y = range_position(c1.getY(),c2.getY(), mapSideLength);
ArrayList<MapBlock> list = new ArrayList<>();
for (double x : range_position_x) {
for (double y : range_position_y) {
Coordinate coordinate = new Coordinate(x,y,z);
MapBlock mapBlock = new MapBlock(coordinate,getMpk(x, y, calculateGly, mapSideLength),calculateGly);
list.add(mapBlock);
}
}
return list;
}
public static String getMpk(Coordinate c,int gly,double mapLength) {
return MapBlock.head + gly + "_"+ mapLength + "(" +c.getX() + ","+ c.getY() + ")";
}
public static String getMpk(double x,double y, int gly,double mapLength) {
return MapBlock.head + gly + "-"+ df.format(mapLength) + "(" +x + ","+ y + ")";
}
public static DecimalFormat df = new DecimalFormat("#0.0000");
/**
* -求兩個點包含圖塊座標範圍
* @param x1 點A
* @param x2 點B
* @param granularity 地圖擴充套件係數
* @return A,B兩點包含的圖塊的一維座標
*/
public static double[] range_position(double x1,double x2,double granularity) {
double minX = Math.min(x1, x2);
double maxX = Math.max(x1, x2);
//左邊界
double left = Math.floor(minX/granularity) * granularity;
//右邊界
double right = Math.ceil(maxX/granularity) * granularity;
//相差
double difference = right - left;
double d_pointNumber = difference/granularity;
//一維座標數
int pointNumber = (int) (int)Math.ceil(Double.valueOf(df.format(d_pointNumber)));
double[] points = new double[pointNumber];
points[0] = Double.valueOf(df.format(left + granularity/2));
for(int i = 1; i<pointNumber; i++) {
points[i] = Double.valueOf(df.format(points[i-1] + granularity));
}
return points;
}
public static void main(String[] args) {
Coordinate A = new Coordinate(118.21,29.11,5);
Coordinate B = new Coordinate(120.30,30.33,5);
List<MapBlock> rangeMapBlock = getRangeMapBlock(A, B);
System.out.println("座標測試 A:" + A + " B:" + B);
System.out.println("包含圖塊:");
for (MapBlock mapBlock : rangeMapBlock) {
System.out.println(mapBlock);
}
System.out.println("size" + rangeMapBlock.size());
Coordinate CNA = new Coordinate(73.33,3.51,5);
Coordinate CNB = new Coordinate(135.05,53.33,5);
System.out.println("-----------------");
System.out.println("-----------------");
System.out.println("-----------------");
List<MapBlock> chineseMapBlock = getRangeMapBlock(CNA,CNB);
System.out.println("中國座標 A:" + CNA + " B:" + CNB);
System.out.println("包含圖塊:");
for (MapBlock mapBlock : chineseMapBlock) {
System.out.println(mapBlock);
}
System.out.println("size" + chineseMapBlock.size());
}
}
描述物件
Coordinate 座標
表示在地圖上的位置
package net.narule.algorithm.map;
/**
* -coordinate 定位物件
* @author Narule
*
*/
public class Coordinate {
private double x;
private double y;
private double z;
public Coordinate() {
super();
}
public Coordinate(double x, double y, double z) {
super();
this.x = x;
this.y = y;
this.z = z;
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
public double getZ() {
return z;
}
public void setZ(double z) {
this.z = z;
}
@Override
public String toString() {
return "Coordinate [x=" + x + ", y=" + y + ", z=" + z + "]";
}
}
Granularity 縮放係數
地圖縮放大小,標尺
package net.narule.algorithm.map;
/**
* -granularity 粒度
* @author Narule
*
*/
public class Granularity {
/**
* -縮放級別
*/
private static int gly;
/**
* -最小單位
* 地球赤道40075千米
* 經緯度中 0.01有 1.1 千米
* 0.001 100m
* 0.0001 10m
* 10m
*/
public static final double unit_length = 0.0001;
public static double unit_granularity = Math.sqrt(Math.pow(unit_length, 2)*2);
/**
* -塊圖邊長
*/
private static double mapSideLength;
/**
* -計算縮放級別
* @param c1
* @param c2
* @return
*/
public static int calculateGly(Coordinate c1,Coordinate c2) {
double x = Math.abs(c1.getX() - c2.getX());
double y = Math.abs(c1.getY() - c2.getY());
double minL = Math.min(x, y);
gly = (int) Math.ceil(
minL/unit_granularity
);
if(gly <= 10) gly = 10;
else if(gly > 10 && gly < 100) gly = gly / 10 * 10;
else if(gly > 100 && gly < 1000) gly = gly / 100 * 100;
else if(gly > 1000) gly = gly / 1000 * 1000;
return gly;
}
public static double getGly() {
return gly;
}
public double getMapSideLength() {
return mapSideLength;
}
}
MapBlock 圖塊
將地圖分割成更小的圖塊,每一塊都包含座標和縮放係數,通過座標和縮放係數能確定唯一
package net.narule.algorithm.map;
import java.io.Serializable;
/*
* -地圖塊
*/
public class MapBlock implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
public static final String head = "mpk-";
private Coordinate position;
private String key;
private int level;
public MapBlock(Coordinate coordinate){
this.position = coordinate;
}
public MapBlock(Coordinate coordinate,String key,int level){
this.position = coordinate;
this.key = key;
this.level = level;
}
public Coordinate getPosition() {
return position;
}
public void setPosition(Coordinate position) {
this.position = position;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
@Override
public String toString() {
return "MapBlock [position=" + position + ", key=" + key + ", level=" + level + "]";
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
}