This commit is contained in:
wangcongtao
2020-10-25 15:51:28 +08:00
40 changed files with 946 additions and 92 deletions

View File

@@ -0,0 +1,149 @@
package com.mogo.commons.utils;
import java.text.DecimalFormat;
/**
* 莫顿编码
*
* @author linyang
* @since 2020.07.09
*/
public class MortonCode {
/**
* morton 转 经纬度 时的中间常量
*/
private static final long NDS_180_DEGREES = 0x7fffffff;
/**
* morton 转 经纬度 时的中间常量
*/
private static final long NDS_360_DEGREES = 4294967295L;
/**
* morton 转 经纬度 时的中间常量
*/
private static final long NDS_90_DEGREES = 0x3fffffff;
/**
* 经纬度转 morton 时的中间常量
*/
private static final double RULE_MORTON = Math.pow( 2, 32 ) / 360;
/**
* morton 转 经纬度 时的中间常量
*/
private static final double RULE_MORTON_TO_LONLAT = 360.0 / Math.pow( 2, 32 );
/**
* @param lon
* @param lat
* @return
*/
public static long wrapEncodeMorton( Double lon, Double lat ) {
DecimalFormat decimalFormat = new DecimalFormat( "#.######" );
return encodeMorton( Double.valueOf( decimalFormat.format( lon ) ),
Double.valueOf( decimalFormat.format( lat ) ) );
}
/**
* 编码 morton code
*
* @param lon
* @param lat
* @return
*/
public static long encodeMorton( Double lon, Double lat ) {
Long bit = 1L;
long mortonCode = 0L;
long x = ( long ) ( lon * RULE_MORTON );
long y = ( long ) ( lat * RULE_MORTON );
if ( y < 0 ) {
y += 0x7FFFFFFF;
}
y = y << 1;
for ( int i = 0; i < 32; i++ ) {
// x-part
mortonCode = mortonCode | ( x & bit );
x = x << 1;
bit = bit << 1;
// y-part
mortonCode = mortonCode | ( y & bit );
y = y << 1;
bit = bit << 1;
}
return mortonCode;
}
/**
* 将莫顿码解码为坐标
*
* @param mortonCode
* @return
*/
public static double[] decodeMorton( long mortonCode ) {
long[] midPoint = mortonCodeToCoord( mortonCode );
normalizeCoord( midPoint );
double[] point = new double[2];
// 将经纬度长整数转化为 浮点类型
point[0] = midPoint[0] * RULE_MORTON_TO_LONLAT;
point[1] = midPoint[1] * RULE_MORTON_TO_LONLAT;
return point;
}
/**
* 莫顿码分别拆解为 编码后的经纬度长整数
*
* @param mortonCode
* @return
*/
private static long[] mortonCodeToCoord( long mortonCode ) {
long bit = 1L;
long[] longPoint = new long[2];
for ( int i = 0; i < 32; i++ ) {
longPoint[0] |= mortonCode & bit;
mortonCode >>= 1;
longPoint[1] |= mortonCode & bit;
bit <<= 1;
}
return longPoint;
}
/**
* 对编码后的经纬度长整数进行解码
*
* @param midPoint
*/
private static void normalizeCoord( long[] midPoint ) {
// if x > 180 degrees, then subtract 360 degrees
if ( midPoint[0] > NDS_180_DEGREES ) {
midPoint[0] -=
NDS_360_DEGREES + 1; // add 1 because 0 must be counted as well
} else if ( midPoint[0] < -NDS_180_DEGREES ) // if x < 180 , x += 360
{
midPoint[0] +=
NDS_360_DEGREES + 1; // add 1 because 0 must be counted as well
}
// if y > 90 degrees, then subtract 180 degrees
if ( midPoint[1] > NDS_90_DEGREES ) {
midPoint[1] -=
NDS_180_DEGREES + 1; // add 1 because 0 must be counted as well
} else if ( midPoint[1] < -NDS_90_DEGREES ) // if y < 90, y += 180
{
midPoint[1] +=
NDS_180_DEGREES + 1; // add 1 because 0 must be counted as well
}
return;
}
public static void main( String[] args ) {
System.out.println( encodeMorton( 116.39584, 39.98152 ) );
}
}