import java.math.BigDecimal;
/**
* 网格编号工具类<br>
* 一、业务数据坐标网格编号计算 <br>
* 1)基于覆盖全国的要求,地理坐标以左下角为原点,采用经度72°及纬度 0°为网格坐标原点进行网格划分<br>
* 2)根据不同的比例尺要求,将网格切分成不同的级别,并按照4x4进行逐级进行切割,精度保留到小数点后10位<br>
* 3)从原点开始计算(原点处坐标为72°,0°),根据网格范围进行行列号换算,其中一次网格行号和列号采用1位或2位数据表示( 0,1,2,3,4…),其他均采用1位数表达(0,1,2,3)<br>
* 二、计算最小网格的中心点坐标<br>
* 1)通过入参确定需要计算的最小网格中心点坐标 <br>
* 2)先计算出一次网格的跨度,如果有更小的网格则累加起来,并取最后一个网格的半个跨度
*
*/
public final class GridCodeUtil {
/** 网格化原点经度72° */
public static final double ORIGIN_X = 72d;
/** 网格化原点纬度 0° */
public static final double ORIGIN_Y = 0d;
/** 网格化终点经度 136° */
public static final double END_X = 136d;
/** 网格化终点纬度 54° */
private static final double END_Y = 54d;
/** 网格化无效值 */
public static final int INVALID_VALUE = -1;
/** 一次网格大小,即经度 1度,纬度1度 */
public static final double FIRST_GRID_SIZE = 1d;
/** 二次网格大小,即经度0.25度,纬度0.25度 */
public static final double SECOND_GRID_SIZE = 0.25d;
/** 三次网格大小,即经度0.0625度,纬度0.0625度 */
public static final double THIRD_GRID_SIZE = 0.0625d;
/** 四次网格大小,即经度0.015625度,纬度0.015625度 */
public static final double FOURTH_GRID_SIZE = 0.015625d;
/** 五次网格大小,即经度0.00390625度,纬度0.00390625度 */
public static final double FIFTH_GRID_SIZE = 0.00390625d;
/** 六次网格大小,即经度0.0009765625度,纬度0.0009765625度 */
public static final double SIXTH_GRID_SIZE = 0.0009765625d;
/** 一次网格折半大小 */
public static final double FIRST_GRID_HALF_SIZE = FIRST_GRID_SIZE / 2;
/** 二次网格折半大小 */
public static final double SECOND_GRID_HALF_SIZE = SECOND_GRID_SIZE / 2;
/** 三次网格折半大小 */
public static final double THIRD_GRID_HALF_SIZE = THIRD_GRID_SIZE / 2;
/** 四次网格折半大小 */
public static final double FOURTH_GRID_HALF_SIZE = FOURTH_GRID_SIZE / 2;
/** 五次网格折半大小 */
public static final double FIFTH_GRID_HALF_SIZE = FIFTH_GRID_SIZE / 2;
/** 六次网格折半大小 */
public static final double SIXTH_GRID_HALF_SIZE = SIXTH_GRID_SIZE / 2;
/** 私有构造函数 */
private GridCodeUtil() {
}
/**
* 坐标网格编号计算
*
* @param xcoord 点的x坐标值,即经度
* @param ycoord 点的y坐标值,即纬度
* @return
*/
public static GridCode computeGridCode(Double xcoord, Double ycoord) {
GridCode result = new GridCode();
boolean isNullOrOutOfRange4x = xcoord == null || xcoord < ORIGIN_X || xcoord > END_X;
boolean isNullOrOutOfRange4y = ycoord == null || ycoord < ORIGIN_Y || ycoord > END_Y;
// 校验是否合法的坐标
if (isNullOrOutOfRange4x || isNullOrOutOfRange4y) {
result.setInvalidValue(INVALID_VALUE);
} else {
result.setFirstGridRowCode(computeRowCodeOfFirstGrid(ycoord));
result.setFirstGridColCode(computeColumnCodeOfFirstGrid(xcoord));
result.setSecondGridRowCode(computeRowCodeOfSecondGrid(ycoord));
result.setSecondGridColCode(computeColumnCodeOfSecondGrid(xcoord));
result.setThirdGridRowCode(computeRowCodeOfThirdGrid(ycoord));
result.setThirdGridColCode(computeColumnCodeOfThirdGrid(xcoord));
result.setFourthGridRowCode(computeRowCodeOfFourthGrid(ycoord));
result.setFourthGridColCode(computeColumnCodeOfFourthGrid(xcoord));
result.setFifthGridRowCode(computeRowCodeOfFifthGrid(ycoord));
result.setFifthGridColCode(computeColumnCodeOfFifthGrid(xcoord));
result.setSixthGridRowCode(computeRowCodeOfSixthGrid(ycoord));
result.setSixthGridColCode(computeColumnCodeOfSixthGrid(xcoord));
}
return result;
}
/**
* 计算最小网格的中心点坐标
*
* @param gridCode 网格编号对象
* @return 中心点坐标,数组的第一个值是x坐标,第二个值是y坐标
*/
public static Double[] computeCentrePointOfMinGrid(GridCode gridCode) {
Double xcoord = null;
Double ycoord = null;
int minGrid = 0;
// 先计算出一次网格的跨度,如果有更小的网格则累加起来。因网格计算时,编号是从0开始的,因此不需要减去一
if (gridCode.getFirstGridColCode() != null && gridCode.getFirstGridRowCode() != null) {
xcoord = gridCode.getFirstGridColCode() * FIRST_GRID_SIZE;
ycoord = gridCode.getFirstGridRowCode() * FIRST_GRID_SIZE;
minGrid = 1;
} else {
// 如果连最基本的一次网格编号都为空,直接抛出参数异常
throw new IllegalArgumentException("计算最小网格的中心点坐标时,传入的一次网格编号不能为空!");
}
if (gridCode.getSecondGridColCode() != null && gridCode.getSecondGridRowCode() != null) {
xcoord += gridCode.getSecondGridColCode() * SECOND_GRID_SIZE;
ycoord += gridCode.getSecondGridRowCode() * SECOND_GRID_SIZE;
minGrid = 2;
}
if (gridCode.getThirdGridColCode() != null && gridCode.getThirdGridRowCode() != null) {
// 如果二次网格编号为空,直接抛出参数异常
if (minGrid != 2) {
throw new IllegalArgumentException("计算最小网格的中心点坐标时,传入的二次网格编号不能为空!");
}
xcoord += gridCode.getThirdGridColCode() * THIRD_GRID_SIZE;
ycoord += gridCode.getThirdGridRowCode() * THIRD_GRID_SIZE;
minGrid = 3;
}
if (gridCode.getFourthGridColCode() != null && gridCode.getFourthGridRowCode() != null) {
// 如果三次网格编号为空,直接抛出参数异常
if (minGrid != 3) {
throw new IllegalArgumentException("计算最小网格的中心点坐标时,传入的三次网格编号不能为空!");
}
xcoord += gridCode.getFourthGridColCode() * FOURTH_GRID_SIZE;
ycoord += gridCode.getFourthGridRowCode() * FOURTH_GRID_SIZE;
minGrid = 4;
}
if (gridCode.getFifthGridColCode() != null && gridCode.getFifthGridRowCode() != null) {
// 如果四次网格编号为空,直接抛出参数异常
if (minGrid != 4) {
throw new IllegalArgumentException("计算最小网格的中心点坐标时,传入的四次网格编号不能为空!");
}
xcoord += gridCode.getFifthGridColCode() * FIFTH_GRID_SIZE;
ycoord += gridCode.getFifthGridRowCode() * FIFTH_GRID_SIZE;
minGrid = 5;
}
if (gridCode.getSixthGridColCode() != null && gridCode.getSixthGridRowCode() != null) {
// 如果五次网格编号为空,直接抛出参数异常
if (minGrid != 5) {
throw new IllegalArgumentException("计算最小网格的中心点坐标时,传入的五次网格编号不能为空!");
}
xcoord += gridCode.getSixthGridColCode() * SIXTH_GRID_SIZE;
ycoord += gridCode.getSixthGridRowCode() * SIXTH_GRID_SIZE;
minGrid = 6;
}
return buildResult(xcoord, ycoord, minGrid);
}
/**
* 计算指定的网格的中心点坐标
*
* @param gridCode 网格编号对象
* @param minGrid 要计算的网格层级
* @return 中心点坐标,数组的第一个值是x坐标,第二个值是y坐标
*/
public static Double[] computeCentrePointOfMinGrid2(GridCode gridCode,int minGrid) {
Double xcoord = null;
Double ycoord = null;
if (minGrid == 1) {
xcoord = gridCode.getFirstGridColCode() * FIRST_GRID_SIZE;
ycoord = gridCode.getFirstGridRowCode() * FIRST_GRID_SIZE;
}
if (minGrid == 2) {
xcoord += gridCode.getSecondGridColCode() * SECOND_GRID_SIZE;
ycoord += gridCode.getSecondGridRowCode() * SECOND_GRID_SIZE;
}
if (minGrid == 3) {
xcoord += gridCode.getThirdGridColCode() * THIRD_GRID_SIZE;
ycoord += gridCode.getThirdGridRowCode() * THIRD_GRID_SIZE;
}
if (minGrid == 4) {
xcoord += gridCode.getFourthGridColCode() * FOURTH_GRID_SIZE;
ycoord += gridCode.getFourthGridRowCode() * FOURTH_GRID_SIZE;
}
if (minGrid == 5) {
xcoord += gridCode.getFifthGridColCode() * FIFTH_GRID_SIZE;
ycoord += gridCode.getFifthGridRowCode() * FIFTH_GRID_SIZE;
minGrid = 5;
}
if (minGrid == 6) {
xcoord += gridCode.getSixthGridColCode() * SIXTH_GRID_SIZE;
ycoord += gridCode.getSixthGridRowCode() * SIXTH_GRID_SIZE;
}
try {
return buildResult(xcoord, ycoord, minGrid);
} catch (Exception e) {
return null;
}
}
/**
* 构建最后的结果值<br>
* 添加网格化原点经纬度和最小网格的中点跨度,如果小数点大于八位,则四舍五入保留八位小数点
*
* @param xcoord 网格跨度x坐标值
* @param ycoord 网格跨度y坐标值
* @param minGrid 需要计算的最小网格
* @return
*/
private static Double[] buildResult(Double xcoord, Double ycoord, int minGrid) {
Double[] result = new Double[2];
result[0] = ORIGIN_X + xcoord;
result[1] = ORIGIN_Y + ycoord;
switch (minGrid) {
case 1:
result[0] += FIRST_GRID_HALF_SIZE;
result[1] += FIRST_GRID_HALF_SIZE;
break;
case 2:
result[0] += SECOND_GRID_HALF_SIZE;
result[1] += SECOND_GRID_HALF_SIZE;
break;
case 3:
result[0] += THIRD_GRID_HALF_SIZE;
result[1] += THIRD_GRID_HALF_SIZE;
break;
case 4:
result[0] += FOURTH_GRID_HALF_SIZE;
result[1] += FOURTH_GRID_HALF_SIZE;
break;
case 5:
result[0] += FIFTH_GRID_HALF_SIZE;
result[1] += FIFTH_GRID_HALF_SIZE;
break;
case 6:
result[0] += SIXTH_GRID_HALF_SIZE;
result[1] += SIXTH_GRID_HALF_SIZE;
break;
default:
throw new IllegalArgumentException("计算最小网格的中心点坐标异常,当前只支持1-6次网格!");
}
BigDecimal bd0 = new BigDecimal(result[0]);
BigDecimal bd1 = new BigDecimal(result[1]);
result[0] = bd0.setScale(8, BigDecimal.ROUND_HALF_UP).doubleValue();
result[1] = bd1.setScale(8, BigDecimal.ROUND_HALF_UP).doubleValue();
return result;
}
/**
* 计算一次网格的行编号
*
* @param ycoord 点的y坐标值,即纬度
* @return
*/
private static int computeRowCodeOfFirstGrid(double ycoord) {
return (int) (difOriginY(ycoord) / FIRST_GRID_SIZE);
}
/**
* 计算一次网格的列编号
*
* @param xcoord 点的x坐标值,即经度
* @return
*/
private static int computeColumnCodeOfFirstGrid(double xcoord) {
return (int) (difOriginX(xcoord) / FIRST_GRID_SIZE);
}
/**
* 获取当前一次网格最小y坐标值
*
* @param ycoord 点的y坐标值,即纬度
* @return
*/
private static double getMiniYcoodOfFirstGrid(double ycoord) {
return computeRowCodeOfFirstGrid(ycoord) * FIRST_GRID_SIZE;
}
/**
* 获取当前一次网格最小x坐标值
*
* @param xcoord 点的x坐标值,即经度
* @return
*/
private static double getMiniXcoodOfFirstGrid(double xcoord) {
return computeColumnCodeOfFirstGrid(xcoord) * FIRST_GRID_SIZE;
}
/**
* 计算二次网格的行编号
*
* @param ycoord 点的y坐标值,即纬度
* @return
*/
private static int computeRowCodeOfSecondGrid(double ycoord) {
return (int) ((difOriginY(ycoord) - getMiniYcoodOfFirstGrid(ycoord)) / SECOND_GRID_SIZE);
}
/**
* 计算二次网格的列编号
*
* @param xcoord 点的x坐标值,即经度
* @return
*/
private static int computeColumnCodeOfSecondGrid(double xcoord) {
return (int) ((difOriginX(xcoord) - getMiniXcoodOfFirstGrid(xcoord)) / SECOND_GRID_SIZE);
}
/**
* 获取当前二次网格最小y坐标值
*
* @param ycoord 点的y坐标值,即纬度
* @return
*/
private static double getMiniYcoodOfSecondGrid(double ycoord) {
return computeRowCodeOfSecondGrid(ycoord) * SECOND_GRID_SIZE;
}
/**
* 获取当前二次网格最小x坐标值
*
* @param xcoord 点的x坐标值,即经度
* @return
*/
private static double getMiniXcoodOfSecondGrid(double xcoord) {
return computeColumnCodeOfSecondGrid(xcoord) * SECOND_GRID_SIZE;
}
/**
* 计算三次网格的行编号
*
* @param ycoord 点的y坐标值,即纬度
* @return
*/
private static int computeRowCodeOfThirdGrid(double ycoord) {
return (int) ((difOriginY(ycoord) - getMiniYcoodOfFirstGrid(ycoord) - getMiniYcoodOfSecondGrid(ycoord))
/ THIRD_GRID_SIZE);
}
/**
* 计算三次网格的列编号
*
* @param xcoord 点的x坐标值,即经度
* @return
*/
private static int computeColumnCodeOfThirdGrid(double xcoord) {
return (int) ((difOriginX(xcoord) - getMiniXcoodOfFirstGrid(xcoord) - getMiniXcoodOfSecondGrid(xcoord))
/ THIRD_GRID_SIZE);
}
/**
* 获取当前三次网格最小y坐标值
*
* @param ycoord 点的y坐标值,即纬度
* @return
*/
private static double getMiniYcoodOfThirdGrid(double ycoord) {
return computeRowCodeOfThirdGrid(ycoord) * THIRD_GRID_SIZE;
}
/**
* 获取当前三次网格最小x坐标值
*
* @param xcoord 点的x坐标值,即经度
* @return
*/
private static double getMiniXcoodOfThirdGrid(double xcoord) {
return computeColumnCodeOfThirdGrid(xcoord) * THIRD_GRID_SIZE;
}
/**
* 计算四次网格的行编号
*
* @param ycoord 点的y坐标值,即纬度
* @return
*/
private static int computeRowCodeOfFourthGrid(double ycoord) {
return (int) ((difOriginY(ycoord) - getMiniYcoodOfFirstGrid(ycoord) - getMiniYcoodOfSecondGrid(ycoord)
- getMiniYcoodOfThirdGrid(ycoord)) / FOURTH_GRID_SIZE);
}
/**
* 计算四次网格的列编号
*
* @param xcoord 点的x坐标值,即经度
* @return
*/
private static int computeColumnCodeOfFourthGrid(double xcoord) {
return (int) ((difOriginX(xcoord) - getMiniXcoodOfFirstGrid(xcoord) - getMiniXcoodOfSecondGrid(xcoord)
- getMiniXcoodOfThirdGrid(xcoord)) / FOURTH_GRID_SIZE);
}
/**
* 获取当前四次网格最小y坐标值
*
* @param ycoord 点的y坐标值,即纬度
* @return
*/
private static double getMiniYcoodOfFourthGrid(double ycoord) {
return computeRowCodeOfFourthGrid(ycoord) * FOURTH_GRID_SIZE;
}
/**
* 获取当前四次网格最小x坐标值
*
* @param xcoord 点的x坐标值,即经度
* @return
*/
private static double getMiniXcoodOfFourthGrid(double xcoord) {
return computeColumnCodeOfFourthGrid(xcoord) * FOURTH_GRID_SIZE;
}
/**
* 计算五次网格的行编号
*
* @param ycoord 点的y坐标值,即纬度
* @return
*/
private static int computeRowCodeOfFifthGrid(double ycoord) {
return (int) ((difOriginY(ycoord) - getMiniYcoodOfFirstGrid(ycoord) - getMiniYcoodOfSecondGrid(ycoord)
- getMiniYcoodOfThirdGrid(ycoord) - getMiniYcoodOfFourthGrid(ycoord)) / FIFTH_GRID_SIZE);
}
/**
* 计算五次网格的列编号
*
* @param xcoord 点的x坐标值,即经度
* @return
*/
private static int computeColumnCodeOfFifthGrid(double xcoord) {
return (int) ((difOriginX(xcoord) - getMiniXcoodOfFirstGrid(xcoord) - getMiniXcoodOfSecondGrid(xcoord)
- getMiniXcoodOfThirdGrid(xcoord) - getMiniXcoodOfFourthGrid(xcoord)) / FIFTH_GRID_SIZE);
}
/**
* 获取当前五次网格最小y坐标值
*
* @param ycoord 点的y坐标值,即纬度
* @return
*/
private static double getMiniYcoodOfFifthGrid(double ycoord) {
return computeRowCodeOfFifthGrid(ycoord) * FIFTH_GRID_SIZE;
}
/**
* 获取当前五次网格最小x坐标值
*
* @param xcoord 点的x坐标值,即经度
* @return
*/
private static double getMiniXcoodOfFifthGrid(double xcoord) {
return computeColumnCodeOfFifthGrid(xcoord) * FIFTH_GRID_SIZE;
}
/**
* 计算六次网格的行编号
*
* @param ycoord 点的y坐标值,即纬度
* @return
*/
private static int computeRowCodeOfSixthGrid(double ycoord) {
return (int) ((difOriginY(ycoord) - getMiniYcoodOfFirstGrid(ycoord) - getMiniYcoodOfSecondGrid(ycoord)
- getMiniYcoodOfThirdGrid(ycoord) - getMiniYcoodOfFourthGrid(ycoord) - getMiniYcoodOfFifthGrid(ycoord))
/ SIXTH_GRID_SIZE);
}
/**
* 计算六次网格的列编号
*
* @param xcoord 点的x坐标值,即经度
* @return
*/
private static int computeColumnCodeOfSixthGrid(double xcoord) {
return (int) ((difOriginX(xcoord) - getMiniXcoodOfFirstGrid(xcoord) - getMiniXcoodOfSecondGrid(xcoord)
- getMiniXcoodOfThirdGrid(xcoord) - getMiniXcoodOfFourthGrid(xcoord) - getMiniXcoodOfFifthGrid(xcoord))
/ SIXTH_GRID_SIZE);
}
/**
* 目标点和原点的纬度差值
*
* @param ycoord 点的y坐标值,即纬度
* @return
*/
private static double difOriginY(double ycoord) {
return ycoord - ORIGIN_Y;
}
/**
* 目标点和原点的经度差值
*
* @param xcoord 点的x坐标值,即经度
* @return
*/
private static double difOriginX(double xcoord) {
return xcoord - ORIGIN_X;
}
}
public class GridCode {
/** 一次网格行号 */
private Integer firstGridRowCode;
/** 一次网格列号 */
private Integer firstGridColCode;
/** 二次网格行号 */
private Integer secondGridRowCode;
/** 二次网格列号 */
private Integer secondGridColCode;
/** 三次网格行号 */
private Integer thirdGridRowCode;
/** 三次网格列号 */
private Integer thirdGridColCode;
/** 四次网格行号 */
private Integer fourthGridRowCode;
/** 四次网格列号 */
private Integer fourthGridColCode;
/** 五次网格行号 */
private Integer fifthGridRowCode;
/** 五次网格列号 */
private Integer fifthGridColCode;
/** 六次网格行号 */
private Integer sixthGridRowCode;
/** 六次网格列号 */
private Integer sixthGridColCode;
/**
* 设置无效值
*/
public void setInvalidValue(int invalidValue) {
this.firstGridRowCode = invalidValue;
this.firstGridColCode = invalidValue;
this.secondGridRowCode = invalidValue;
this.secondGridColCode = invalidValue;
this.thirdGridRowCode = invalidValue;
this.thirdGridColCode = invalidValue;
this.fourthGridRowCode = invalidValue;
this.fourthGridColCode = invalidValue;
this.fifthGridRowCode = invalidValue;
this.fifthGridColCode = invalidValue;
this.sixthGridRowCode = invalidValue;
this.sixthGridColCode = invalidValue;
}
public Integer getFirstGridRowCode() {
return firstGridRowCode;
}
public void setFirstGridRowCode(Integer firstGridRowCode) {
this.firstGridRowCode = firstGridRowCode;
}
public Integer getFirstGridColCode() {
return firstGridColCode;
}
public void setFirstGridColCode(Integer firstGridColCode) {
this.firstGridColCode = firstGridColCode;
}
public Integer getSecondGridRowCode() {
return secondGridRowCode;
}
public void setSecondGridRowCode(Integer secondGridRowCode) {
this.secondGridRowCode = secondGridRowCode;
}
public Integer getSecondGridColCode() {
return secondGridColCode;
}
public void setSecondGridColCode(Integer secondGridColCode) {
this.secondGridColCode = secondGridColCode;
}
public Integer getThirdGridRowCode() {
return thirdGridRowCode;
}
public void setThirdGridRowCode(Integer thirdGridRowCode) {
this.thirdGridRowCode = thirdGridRowCode;
}
public Integer getThirdGridColCode() {
return thirdGridColCode;
}
public void setThirdGridColCode(Integer thirdGridColCode) {
this.thirdGridColCode = thirdGridColCode;
}
public Integer getFourthGridRowCode() {
return fourthGridRowCode;
}
public void setFourthGridRowCode(Integer fourthGridRowCode) {
this.fourthGridRowCode = fourthGridRowCode;
}
public Integer getFourthGridColCode() {
return fourthGridColCode;
}
public void setFourthGridColCode(Integer fourthGridColCode) {
this.fourthGridColCode = fourthGridColCode;
}
public Integer getFifthGridRowCode() {
return fifthGridRowCode;
}
public void setFifthGridRowCode(Integer fifthGridRowCode) {
this.fifthGridRowCode = fifthGridRowCode;
}
public Integer getFifthGridColCode() {
return fifthGridColCode;
}
public void setFifthGridColCode(Integer fifthGridColCode) {
this.fifthGridColCode = fifthGridColCode;
}
public Integer getSixthGridRowCode() {
return sixthGridRowCode;
}
public void setSixthGridRowCode(Integer sixthGridRowCode) {
this.sixthGridRowCode = sixthGridRowCode;
}
public Integer getSixthGridColCode() {
return sixthGridColCode;
}
public void setSixthGridColCode(Integer sixthGridColCode) {
this.sixthGridColCode = sixthGridColCode;
}
}