The longitude and latitude coordinates are used as the center point to generate a circular surface with a distance of meters and a radius of length, including java js source code + online drawing, and the code is simple and zero-dependent

When updating my coordinate boundary query tool some time ago, I needed to use the distance calculation of latitude and longitude coordinate points, and generate a circle with a specified distance as the center centered on the coordinate point. I searched and found no ready-made simple and suitable code. , so I dug out the code at the bottom of the box, simplified and improved it, hey, the amount of code is not large, and it is quite easy to use.

This method is to obtain an approximate circular surface by calculating multiple coordinate points on the circle. As long as there are enough coordinate points, the circle can be round enough; with these coordinate points, it is easy to express in different formats , such as: GeoJSON文本, WKT文本, Geometry实例.

From the open source library of coordinate boundary query tools: https://github.com/xiangyuecn/AreaCity-Query-Geometry (github can be replaced by gitee), high-performance coordinate data, boundary data query tools, Java open source programs, with http query Interface, low memory usage (you can check the city information corresponding to more than 10,000 coordinates in 1 second).

java version source code

public static void main(String[] args) {
    
    
	//计算天坛到天安门的距离
	System.out.println(Distance(116.410622, 39.881773, 116.397476, 39.908647));
	//生成天坛1公里范围的圆形面
	System.out.println(CreateSimpleCircleWKT(116.410622, 39.881773, 1000, 24));
}

/** 计算两个坐标的距离,单位米 **/
static public double Distance(double lng1, double lat1, double lng2, double lat2) {
    
    
	//采用Haversine formula算法,高德地图的js计算代码,比较简洁 https://www.cnblogs.com/ggz19/p/7551088.html
	double d=Math.PI/180;
	double f=lat1*d, h=lat2*d;
	double i=lng2*d - lng1*d;
	double e=(1 - Math.cos(h - f) + (1 - Math.cos(i)) * Math.cos(f) * Math.cos(h)) / 2;
	return 2 * 6378137 * Math.asin(Math.sqrt(e));
}

/** 以坐标点为中心,简单粗略的创建一个指定半径的圆,半径单位米,pointCount为构建圆的坐标点数(比如24个点,点越多越圆,最少3个点),返回构成圆的坐标点数组 **/
static public double[][] CreateSimpleCircle(double lng, double lat, double radius, int pointCount) {
    
    
	//球面坐标不会算,转换成三角坐标简单点,经度代表值大约:0.01≈1km 0.1≈10km 1≈100km 10≈1000km
	double km=radius/1000;
	double a=km<5?0.01 :km<50?0.1 :km<500?1 :10;
	double b=Distance(lng, lat, lng+a, lat);
	double c=Distance(lng, lat, lng, lat+a);
	double rb=radius/b*a;
	double rc=radius/c*a;
	double[][] arr=new double[pointCount+1][];
	double n=0,step=360.0/pointCount,N=360-step/2; //注意浮点数±0.000000001的差异
	for(int i=0;n<N;i++,n+=step){
    
    
		double x=lng+rb*Math.cos(n*Math.PI/180);
		double y=lat+rc*Math.sin(n*Math.PI/180);
		arr[i]=new double[] {
    
     x, y };
	}
	arr[pointCount]=new double[] {
    
     arr[0][0], arr[0][1] }; //闭环
	return arr;
}

/**
以坐标点为中心,简单粗略的创建一个指定半径的圆,半径单位米,pointCount为构建圆的坐标点数(比如24个点,点越多越圆,最少3个点),返回圆的WKT(Well Known Text)文本
,WKT图形绘制预览工具:https://xiangyuecn.gitee.io/areacity-jsspider-statsgov/assets/geo-echarts.html
**/
static public String CreateSimpleCircleWKT(double lng, double lat, double radius, int pointCount) {
    
    
	double[][] points=CreateSimpleCircle(lng, lat, radius, pointCount);
	DecimalFormat df=new DecimalFormat("0.######");
	StringBuilder wkt=new StringBuilder("POLYGON((");
	for(int i=0;i<points.length;i++) {
    
    
		if(i>0)wkt.append(",");
		wkt.append(df.format(points[i][0])+" "+df.format(points[i][1]));
	}
	wkt.append("))");
	return wkt.toString();
}

js version source code

//测试:计算天坛到天安门的距离
console.log(Distance(116.410622, 39.881773, 116.397476, 39.908647));
//测试:生成天坛1公里范围的圆形面
console.log(CreateSimpleCircleWKT(116.410622, 39.881773, 1000, 24));

/** 计算两个坐标的距离,单位米 **/
function Distance(lng1, lat1, lng2, lat2) {
    
    
    //采用Haversine formula算法,高德地图的js计算代码,比较简洁 https://www.cnblogs.com/ggz19/p/7551088.html
    var d=Math.PI/180;
    var f=lat1*d, h=lat2*d;
    var i=lng2*d - lng1*d;
    var e=(1 - Math.cos(h - f) + (1 - Math.cos(i)) * Math.cos(f) * Math.cos(h)) / 2;
    return 2 * 6378137 * Math.asin(Math.sqrt(e));
}

/** 以坐标点为中心,简单粗略的创建一个指定半径的圆,半径单位米,pointCount为构建圆的坐标点数(比如24个点,点越多越圆,最少3个点),返回构成圆的坐标点数组 **/
function CreateSimpleCircle(lng, lat, radius, pointCount){
    
    
	//球面坐标不会算,转换成三角坐标简单点,经度代表值大约:0.01≈1km 0.1≈10km 1≈100km 10≈1000km
	var km=radius/1000;
	var a=km<5?0.01 :km<50?0.1 :km<500?1 :10;
	var b=Distance(lng, lat, lng+a, lat);
	var c=Distance(lng, lat, lng, lat+a);
	var rb=radius/b*a;
	var rc=radius/c*a;
	var arr=[];
	var n=0,step=360.0/pointCount,N=360-step/2; //注意浮点数±0.000000001的差异
	for(var i=0;n<N;i++,n+=step){
    
    
		var x=lng+rb*Math.cos(n*Math.PI/180);
		var y=lat+rc*Math.sin(n*Math.PI/180);
		arr[i]=[x, y];
	}
	arr.push([arr[0][0], arr[0][1]]); //闭环
	return arr;
};

/**
以坐标点为中心,简单粗略的创建一个指定半径的圆,半径单位米,pointCount为构建圆的坐标点数(比如24个点,点越多越圆,最少3个点),返回圆的WKT(Well Known Text)文本
,WKT图形绘制预览工具:https://xiangyuecn.gitee.io/areacity-jsspider-statsgov/assets/geo-echarts.html
**/
function CreateSimpleCircleWKT(lng, lat, radius, pointCount){
    
    
	var points=CreateSimpleCircle(lng, lat, radius, pointCount);
    var wkt=["POLYGON(("];
    for(var i=0;i<points.length;i++) {
    
    
		wkt.push((i>0?",":"")+(+points[i][0].toFixed(6))+" "+(+points[i][1].toFixed(6)));
    }
    wkt.push("))");
    return wkt.join("");
};

Online drawing preview effect

After the WKT text of the circular surface is generated, it can be pasted into the online preview page to draw and display: https://xiangyuecn.gitee.io/areacity-jsspider-statsgov/assets/geo-echarts.html , which is convenient for code debugging, and there are The distance measurement function can measure the accuracy of the circular surface; the circle drawing function on the page uses the js version of the code.

Circular surface display effect of 24 coordinate points

About the accuracy of the calculation

The algorithm used to calculate the distance between two longitude and latitude coordinates Haversine formula, the API of Gaode map in the following calculation code is also Haversine formulathe algorithm, and the error of the calculation result of Baidu map is 0.2%within:

bMap=window.BMapGL&&BMapGL.Map.prototype||{
    
    getDistance:function(a,b){
    
    return BMap.Map.prototype.getDistance(new BMap.Point(a.lng,a.lat),new BMap.Point(b.lng,b.lat)) }};

//地图api计算【纬度】之间的距离,每一度之间的距离是相同的
bMap.getDistance({
    
    lng:111,lat:15},{
    
    lng:111,lat:16})        //百度111194.86米
new AMap.LngLat(111,15).distance(new AMap.LngLat(111,16)) //高德111319.49米

bMap.getDistance({
    
    lng:121,lat:55},{
    
    lng:121,lat:56})        //百度111194.78米
new AMap.LngLat(121,55).distance(new AMap.LngLat(121,56)) //高德111319.49米

//地图api计算【经度】之间的距离,会随着纬度的不同而不同
bMap.getDistance({
    
    lng:111,lat:15},{
    
    lng:112,lat:15})        //百度107405.91米
new AMap.LngLat(111,15).distance(new AMap.LngLat(112,15)) //高德107526.28米

bMap.getDistance({
    
    lng:111,lat:55},{
    
    lng:112,lat:55})        //百度63778.21米
new AMap.LngLat(111,55).distance(new AMap.LngLat(112,55)) //高德63849.69米
        //经度在相同纬度下每一度之间的距离是相同的
        bMap.getDistance({
    
    lng:121,lat:55},{
    
    lng:122,lat:55})        //百度63778.21米
        new AMap.LngLat(121,55).distance(new AMap.LngLat(122,55)) //高德63849.69米

For the calculation of the coordinate points that make up the circle, the code used to press the bottom of the box before is used. The calculation is relatively simple. The longitude and latitude respectively calculate the distance length of one degree, and the degree corresponding to the radius is converted in equal proportions. For example, the calculated longitude 1 ° is 100km, then the degree corresponding to the radius of 20km is 1° * 20 / 100 = 0.2°.

  • The distance between each degree of latitude is a fixed length, and there is no error in the result after proportional conversion.
  • The distance between each degree of longitude will vary with the latitude. Low latitudes are long and high latitudes are short. The upper and lower latitudes of the circular surface are different. When the radius is small, the error is small, and the larger the radius is, the greater the error is.

Therefore, there is no problem in latitude when converted in equal proportions, but there will be some errors in longitude, but as long as the radius of the circle does not exceed 10km, the error can be controlled within, which can be directly calculated and observed by the following code 0.5%:

//经度之间的距离,不同纬度下的误差计算
d1=new AMap.LngLat(111,15.0).distance(new AMap.LngLat(111.2,15.0));
d2=new AMap.LngLat(111,15.2).distance(new AMap.LngLat(111.2,15.2));
console.log(d2, (d1-d2)/d2*100+"%") //低纬度下经度0.2°距离≈20km,纬度0.2°导致0.09%误差
d1=new AMap.LngLat(111,55.0).distance(new AMap.LngLat(111.2,55.0));
d2=new AMap.LngLat(111,55.2).distance(new AMap.LngLat(111.2,55.2));
console.log(d2, (d1-d2)/d2*100+"%") //高纬度下经度0.2°距离≈10km,纬度0.2°导致0.50%误差

d1=new AMap.LngLat(111,15).distance(new AMap.LngLat(112,15));
d2=new AMap.LngLat(111,16).distance(new AMap.LngLat(112,16));
console.log(d2, (d1-d2)/d2*100+"%") //低纬度下经度1°距离≈100km,纬度1°导致0.49%误差
d1=new AMap.LngLat(111,55).distance(new AMap.LngLat(112,55));
d2=new AMap.LngLat(111,56).distance(new AMap.LngLat(112,56));
console.log(d2, (d1-d2)/d2*100+"%") //高纬度下经度1°距离≈60km,纬度1°导致2.57%误差

Because it is a circle obtained by connecting the coordinate points on the circle, it is essentially a polygon that approximates a circle. As long as there are enough coordinate points, it will be closer to a circle. When there are few coordinate points, it is not so circular to the naked eye (minimum 3 coordinate points, triangles), the error will be large. However, considering that the more points there are, the amount of calculations in many places will become very large, so the number of coordinate points forming a circle is also a comprehensive consideration. I choose 24 coordinate points to form a circle, 6 in each quadrant points, the angle between the points is 15°.

【over】

Guess you like

Origin blog.csdn.net/xiangyuecn/article/details/131101713