基於隨機定位的地圖信息獲取方式


基於隨機定位的地圖信息獲取方式

基本定義

場景

一個應用要用到地圖,地圖拖動時,要填補新的版圖上的地理信息

目的

快速獲取屏幕內需要的地圖信息,不獲取多余無用的地圖信息

功能要點

1.確定地圖范圍,獲取的信息不超出顯示屏過多

(比如屏幕地圖查詢100平方米的信息,服務返回的信息不能超過130平米的地圖信息)

2.動態快速獲取信息,通過定位快速獲取周圍地理信息,第一時間從緩存獲取或者數據庫獲取,且不要有復雜查詢和大量查詢。

絕對定位:坐標,傳人任何一個點,都能通過角色定位知道這個點在哪,以及其他延伸計算

通過地圖的中心定位,優先快速確定要獲取那些位置的地理信息,快速獲取對應的圖塊。

3.根據維度調整信息獲取范圍和格式

粒度:通過兩個點確定查詢信息的范圍,同時確定粒度(地圖縮放級別)

(4).原先有的信息短時間不重復獲取

(拖動地圖導致50%地圖位置換了,還有50%地圖不變,不用再次請求)

確定地圖范圍

通過兩個點,或者中心定位+范圍,要快速得出在范圍內地圖信息

地圖切割

分塊

將地圖切割均等大小

塊級別

地圖顯示可以是世界地圖,也可以是城鎮地圖,縮放差距很大,地圖塊也要級別表示具體縮放場景

坐標

一個絕對坐標,作為參考

每一個切割的分塊地圖都有一個坐標,坐標唯一

確定分塊坐標唯一依據:分塊級別,經緯度,

分塊地圖表示方法

獲取范圍內的分塊地圖

矩形對角線兩個點,可以確定范圍

入參:坐標1,坐標2,粒度(地圖縮放級別)

返回:分塊地圖坐標

將問題細分化,可以分解為,先求所有圖塊的x坐標,再求y坐標,然后數組相乘,獲得所有圖塊的二維坐標(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());
	}
}

測試結果

坐標測試 A:(x,y,z):[118.21, 29.11, 5.0] B:(x,y,z):[120.3, 30.33, 5.0]
包含圖塊:
MapBlock [position=(x,y,z):[118.0, 29.2, 5.0], key=mpk-8000-0.8000(118.0,29.2), level=8000]
MapBlock [position=(x,y,z):[118.0, 30.0, 5.0], key=mpk-8000-0.8000(118.0,30.0), level=8000]
MapBlock [position=(x,y,z):[118.8, 29.2, 5.0], key=mpk-8000-0.8000(118.8,29.2), level=8000]
MapBlock [position=(x,y,z):[118.8, 30.0, 5.0], key=mpk-8000-0.8000(118.8,30.0), level=8000]
MapBlock [position=(x,y,z):[119.6, 29.2, 5.0], key=mpk-8000-0.8000(119.6,29.2), level=8000]
MapBlock [position=(x,y,z):[119.6, 30.0, 5.0], key=mpk-8000-0.8000(119.6,30.0), level=8000]
MapBlock [position=(x,y,z):[120.4, 29.2, 5.0], key=mpk-8000-0.8000(120.4,29.2), level=8000]
MapBlock [position=(x,y,z):[120.4, 30.0, 5.0], key=mpk-8000-0.8000(120.4,30.0), level=8000]
size8
-----------------
-----------------
-----------------
中國坐標 A:(x,y,z):[73.33, 3.51, 5.0] B:(x,y,z):[135.05, 53.33, 5.0]
包含圖塊:
MapBlock [position=(x,y,z):[88.0, 17.6, 5.0], key=mpk-352000-35.2000(88.0,17.6), level=352000]
MapBlock [position=(x,y,z):[88.0, 52.8, 5.0], key=mpk-352000-35.2000(88.0,52.8), level=352000]
MapBlock [position=(x,y,z):[123.2, 17.6, 5.0], key=mpk-352000-35.2000(123.2,17.6), level=352000]
MapBlock [position=(x,y,z):[123.2, 52.8, 5.0], key=mpk-352000-35.2000(123.2,52.8), level=352000]
size4

描述對象

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM