package commons.gis import kotlin.math.asin import kotlin.math.atan2 import kotlin.math.cos import kotlin.math.sin import kotlin.math.sqrt import kotlin.math.PI object GeoRectangleUtils { /** * 根据中心点、宽度和高度生成矩形(米为单位)不带方向 */ fun createRectangleFromCenter( centerLng: Double, centerLat: Double, widthMeters: Double = 6.0, heightMeters: Double = 8.0 ): List> { val halfWidth = widthMeters / 2 val halfHeight = heightMeters / 2 // 计算四个角点 val topLeft = calculateDestinationPoint( centerLng, centerLat, 315.0, sqrt(halfWidth * halfWidth + halfHeight * halfHeight) ) val topRight = calculateDestinationPoint( centerLng, centerLat, 45.0, sqrt(halfWidth * halfWidth + halfHeight * halfHeight) ) val bottomRight = calculateDestinationPoint( centerLng, centerLat, 135.0, sqrt(halfWidth * halfWidth + halfHeight * halfHeight) ) val bottomLeft = calculateDestinationPoint( centerLng, centerLat, 225.0, sqrt(halfWidth * halfWidth + halfHeight * halfHeight) ) return listOf(topLeft, topRight, bottomRight, bottomLeft, topLeft) // 闭合 } // 矩形尺寸:半宽1000米,半高500米 /**根据中心的生产矩形,带方向***/ fun generateCenterRect( centerLng: Double, centerLat: Double, direction: Double, halfWidth: Double = 5.0, halfHeight: Double = 5.0 ): List> { // 将方向角转换为数学角度(逆时针从x轴正方向) val angleRad = Math.toRadians(90 - direction) // 计算四个顶点的偏移量(米) val offsets = listOf( // 右上顶点 Pair( halfWidth * cos(angleRad) - halfHeight * sin(angleRad), halfWidth * sin(angleRad) + halfHeight * cos(angleRad) ), // 右下顶点 Pair( halfWidth * cos(angleRad) + halfHeight * sin(angleRad), halfWidth * sin(angleRad) - halfHeight * cos(angleRad) ), // 左下顶点 Pair( -halfWidth * cos(angleRad) + halfHeight * sin(angleRad), -halfWidth * sin(angleRad) - halfHeight * cos(angleRad) ), // 左上顶点 Pair( -halfWidth * cos(angleRad) - halfHeight * sin(angleRad), -halfWidth * sin(angleRad) + halfHeight * cos(angleRad) ), // 右上顶点 Pair( halfWidth * cos(angleRad) - halfHeight * sin(angleRad), halfWidth * sin(angleRad) + halfHeight * cos(angleRad) ), ) // 将米偏移量转换为经纬度坐标 var ps = offsets.map { (dx, dy) -> metersToGeoPoint(centerLng, centerLat, dx, dy) } return ps } /** * 将米单位的偏移量转换为经纬度坐标 */ private fun metersToGeoPoint( centerLng: Double, centerLat: Double, dx: Double, dy: Double ): List { // 地球半径(米) val EARTH_RADIUS = 6378137.0 val latRad = Math.toRadians(centerLat) // 纬度每度对应的米数 val latPerMeter = 1.0 / (PI * EARTH_RADIUS / 180.0) // 经度每度对应的米数(随纬度变化) val lonPerMeter = 1.0 / (PI * EARTH_RADIUS * cos(latRad) / 180.0) val newLat = centerLat + dy * latPerMeter val newLon = centerLng + dx * lonPerMeter return listOf(newLon, newLat) } /** * 根据前方点和方向生成矩形 */ fun createRectangleInFront( frontPoint: List, bearingDegrees: Double, // 方向角度(0-360,0表示北) widthMeters: Double = 3.0, depthMeters: Double = 8.0 ): List> { // 计算矩形中心点(在前方 depthMeters/2 处) val center = calculateDestinationPoint( frontPoint[0], frontPoint[1], bearingDegrees, depthMeters / 2 ) // 垂直于方向的宽度 val perpendicularBearing1 = (bearingDegrees + 90) % 360 val perpendicularBearing2 = (bearingDegrees - 90 + 360) % 360 // 前方点 val frontCenter = calculateDestinationPoint( center[0], center[1], bearingDegrees, depthMeters / 2 ) // 计算四个角点 val frontLeft = calculateDestinationPoint( frontCenter[0], frontCenter[1], perpendicularBearing1, widthMeters / 2 ) val frontRight = calculateDestinationPoint( frontCenter[0], frontCenter[1], perpendicularBearing2, widthMeters / 2 ) val backLeft = calculateDestinationPoint( frontPoint[0], frontCenter[1], perpendicularBearing1, widthMeters / 2 ) val backRight = calculateDestinationPoint( frontPoint[0], frontCenter[1], perpendicularBearing2, widthMeters / 2 ) return listOf(backLeft, frontLeft, frontRight, backRight, backLeft) } /** * 根据中心的生产矩形,带方向 * @param rotation 航向角 */ fun createRotatedRectangleFromCenter( centerLon: Double, centerLat: Double, rotation: Double = 0.0, widthMeters: Double = 100.0, heightMeters: Double = 80.0 ): List> { // 地球半径(米) val EARTH_RADIUS = 6371000.0 // 将米转换为经纬度(近似计算) val latDelta = (heightMeters / 2) / EARTH_RADIUS * (180 / Math.PI) val lonDelta = (widthMeters / 2) / (EARTH_RADIUS * cos(Math.toRadians(centerLat))) * (180 / Math.PI) var result = mutableListOf>() // 左上角 result.add(listOf(centerLon - lonDelta, centerLat + latDelta)) // 右上角 result.add(listOf(centerLon + lonDelta, centerLat + latDelta)) // 右下角 result.add(listOf(centerLon + lonDelta, centerLat - latDelta)) // 左下角 result.add(listOf(centerLon - lonDelta, centerLat - latDelta)) result.add(listOf(centerLon - lonDelta, centerLat + latDelta)) return result } /** * 计算目标点(根据起点、方向和距离) */ private fun calculateDestinationPoint( startLng: Double, startLat: Double, bearing: Double, distanceMeters: Double ): List { val earthRadius = 6371000.0 // 地球半径(米) val startLatRad = Math.toRadians(startLat) val startLngRad = Math.toRadians(startLng) val bearingRad = Math.toRadians(bearing) val endLatRad = asin( sin(startLatRad) * cos(distanceMeters / earthRadius) + cos(startLatRad) * sin(distanceMeters / earthRadius) * cos(bearingRad) ) val endLngRad = startLngRad + atan2( sin(bearingRad) * sin(distanceMeters / earthRadius) * cos(startLatRad), cos(distanceMeters / earthRadius) - sin(startLatRad) * sin(endLatRad) ) return listOf(Math.toDegrees(endLngRad), Math.toDegrees(endLatRad)) } }