使用Java和Proj4j计算两个地理坐标点的最小矩形包围盒
- 引言
- maven引用
- 代码示例
引言
今天小编碰到个需求,要求通过两个坐标点位向外扩大500米半径,通过这两个500米半径的圆给前端地图提供可画出长方形的四个坐标点
maven引用
<dependency>
<groupId>org.osgeo</groupId>
<artifactId>proj4j</artifactId>
<version>0.1.0</version>
</dependency>
代码示例
public class RectangleFromLine {
/**
* 经纬度地理坐标转面坐标
*
* @param lat
* @param lng
* @return
*/
public static double[] coordinateTransformation(double lat, double lng) {
CRSFactory crsFactory = new CRSFactory();
CoordinateReferenceSystem wgs84 = crsFactory.createFromName("EPSG:4326");
CoordinateReferenceSystem webMercator = crsFactory.createFromName("EPSG:3857");
// 创建坐标变换器
CoordinateTransformFactory ctFactory = new CoordinateTransformFactory();
CoordinateTransform transform = ctFactory.createTransform(wgs84, webMercator);
ProjCoordinate srcCoord = new ProjCoordinate(lng, lat);
// 执行转换
ProjCoordinate destCoord = new ProjCoordinate();
transform.transform(srcCoord, destCoord);
return new double[]{destCoord.x, destCoord.y};
}
/**
* 面坐标转地理坐标
*
* @param x
* @param y
* @return
*/
public static double[] coordinateTransformationReversal(double x, double y) {
CRSFactory crsFactory = new CRSFactory();
CoordinateReferenceSystem wgs84 = crsFactory.createFromName("EPSG:4326");
CoordinateReferenceSystem webMercator = crsFactory.createFromName("EPSG:3857");
// 创建坐标变换器
CoordinateTransformFactory ctFactory = new CoordinateTransformFactory();
CoordinateTransform transform = ctFactory.createTransform(webMercator, wgs84);
ProjCoordinate srcCoord = new ProjCoordinate(x, y);
// 执行转换
ProjCoordinate destCoord = new ProjCoordinate();
transform.transform(srcCoord, destCoord);
return new double[]{destCoord.y, destCoord.x};
}
/**
* 取两圆的最小包围盒(正北方向)
*
* @param startLatitude
* @param startLongitude
* @param endLatitude
* @param endLongitude
* @param radius
* @return
*/
public static double[][] calculateRectangleVertices(double startLatitude, double startLongitude, double endLatitude,
double endLongitude, double radius) {
double[] p1 = coordinateTransformation(startLatitude, startLongitude);
double[] p2 = coordinateTransformation(endLatitude, endLongitude);
double[] leftBottom = new double[]{Math.min(p1[0], p2[0]) - radius, Math.min(p1[1], p2[1]) - radius};
//面坐标转地理坐标
double[] leftBottom_1 = coordinateTransformationReversal(leftBottom[0], leftBottom[1]);
double[] leftTop = new double[]{Math.min(p1[0], p2[0]) - radius, Math.max(p1[1], p2[1]) + radius};
//面坐标转地理坐标
double[] leftTop_1 = coordinateTransformationReversal(leftTop[0], leftTop[1]);
double[] rightTop = new double[]{Math.max(p1[0], p2[0]) + radius, Math.max(p1[1], p2[1]) + radius};
//面坐标转地理坐标
double[] rightTop_1 = coordinateTransformationReversal(rightTop[0], rightTop[1]);
double[] rightBottom = new double[]{Math.max(p1[0], p2[0]) + radius, Math.min(p1[1], p2[1]) - radius};
//面坐标转地理坐标
double[] rightBottom_1 = coordinateTransformationReversal(rightBottom[0], rightBottom[1]);
return new double[][]{leftBottom_1, leftTop_1, rightTop_1, rightBottom_1};
}
/**
* 取两圆的最小包围盒(轴方向)
*
* @param startLatitude
* @param startLongitude
* @param endLatitude
* @param endLongitude
* @param radius
* @return
*/
public static double[][] calculateRectangleVertices1(double startLatitude, double startLongitude,
double endLatitude, double endLongitude, double radius) {
double[] p1 = coordinateTransformation(startLatitude, startLongitude);
double[] p2 = coordinateTransformation(endLatitude, endLongitude);
double minX = Math.min(p1[0], p2[0]) - radius;
double maxX = Math.max(p1[0], p2[0]) + radius;
double minY = Math.min(p1[1], p2[1]) - radius;
double maxY = Math.max(p1[1], p2[1]) + radius;
// 计算中心点
double centerX = (minX + maxX) / 2.0;
double centerY = (minY + maxY) / 2.0;
// 计算轴方向
double axisDirection = Math.atan2(maxY - minY, maxX - minX);
// 计算宽度和高度
double width = maxX - minX;
double height = maxY - minY;
// 计算四个顶点
double[][] vertices = new double[4][2];
vertices[0] = calculateVertex(centerX, centerY, width / 2, height / 2, axisDirection, -1, -1);
vertices[1] = calculateVertex(centerX, centerY, width / 2, height / 2, axisDirection, -1, 1);
vertices[2] = calculateVertex(centerX, centerY, width / 2, height / 2, axisDirection, 1, 1);
vertices[3] = calculateVertex(centerX, centerY, width / 2, height / 2, axisDirection, 1, -1);
// 将顶点从Web Mercator坐标转回地理坐标
for (int i = 0; i < 4; i++) {
vertices[i] = coordinateTransformationReversal(vertices[i][0], vertices[i][1]);
}
return vertices;
}
/**
* 计算单个顶点
*
* @param centerX
* 中心点的X坐标
* @param centerY
* 中心点的Y坐标
* @param width
* 包围盒的宽度
* @param height
* 包围盒的高度
* @param angle
* 轴方向(弧度)
* @param dx
* X方向的偏移量(-1或1)
* @param dy
* Y方向的偏移量(-1或1)
* @return 顶点坐标
*/
private static double[] calculateVertex(double centerX, double centerY, double width, double height, double angle,
int dx, int dy) {
double x = centerX + dx * width * Math.cos(angle) - dy * height * Math.sin(angle);
double y = centerY + dx * width * Math.sin(angle) + dy * height * Math.cos(angle);
return new double[]{x, y};
}
}