1. 矩形搜索区域参数化建模与边界校验

任务对象与建模思路

本例的任务是把“给定经纬度范围的矩形任务区”转成后续航线规划可直接消费的标准化区域描述。矩形区域在经纬度坐标下由四个边界值唯一确定:西边界 lon_min、东边界 lon_max、南边界 lat_min、北边界 lat_max。参数化建模的核心不是画一个矩形,而是把边界值整理成带单位、带顶点顺序、带面积周长、带异常标记的结构化对象。

需要特别注意的是,经纬度矩形在球面上并不是平面矩形:经线向北收敛,因此面积不能简单用“经度差×纬度差”计算,而应按球面梯形积分。同时,当 lon_min 与 lon_max 跨越 ±180° 时,直接相减会得到错误宽度;当区域接近极点时,经度方向的实际距离急剧收缩,也需要单独标记。

经纬度矩形与四顶点 P1 西北 P2 东北 P3 东南 P4 西南 lat_max lat_min lon_min lon_max 中心点 标准化区域描述 bounds: lon_min, lon_max, lat_min, lat_max vertices: P1→P2→P3→P4(顺时针) area_km2 / perimeter_km(球面计算) center: 经纬度中心点 flags: dateline_cross / polar_risk valid: true / false + 原因 边界校验分支 lon_min > lon_max ? 跨日期变更线判定 |lat| > 85° ? 极点附近风险 lat_min ≥ lat_max ? 退化区域判定 输出 valid 标记 供航线规划消费 跨日期变更线:宽度 = (lon_max + 360) − lon_min,需归一化到 [0,360) 极点附近:经度方向实际距离按 cos(lat) 收缩,需提示规划器调整航向步长

参数化建模的关键计算

设地球平均半径 R = 6371.0088 km,纬度用弧度表示。矩形区域面积按球面梯形公式计算:

A = R² · |Δλ| · |sin(φ_max) − sin(φ_min)|

其中 Δλ 是经度跨度(弧度),φ_max、φ_min 是南北边界纬度(弧度)。周长由两条纬线弧长与两条经线弧长组成:

L_lat = R · |Δλ| · cos(φ)          (某条纬线上的东西向弧长)
L_lon = R · |Δφ|                    (南北向经线弧长)
P = 2·(L_lat(φ_max) + L_lat(φ_min)) + 2·L_lon

当 lon_min > lon_max 时,说明区域跨越 ±180°,此时经度跨度应取 (lon_max + 360) − lon_min,并把顶点经度统一归一化到 [0, 360) 或 [−180, 180) 后再输出。

可运行的建模与校验实现

下面给出一个自洽的 Python 实现,输入为四个边界值,输出标准化区域描述字典,并完成日期变更线、极点附近、退化区域三类校验。

import math

R = 6371.0088  # 地球平均半径 km

def normalize_lon(lon):
    """归一化经度到 [-180, 180)"""
    return (lon + 180.0) % 360.0 - 180.0

def build_rect_region(lon_min, lon_max, lat_min, lat_max):
    # 1. 基本合法性
    if lat_min >= lat_max:
        return {"valid": False, "reason": "lat_min 必须小于 lat_max"}
    if lat_min < -90 or lat_max > 90:
        return {"valid": False, "reason": "纬度超出 [-90, 90]"}
    if lon_min < -180 or lon_max > 180:
        return {"valid": False, "reason": "经度超出 [-180, 180]"}

    # 2. 日期变更线判定
    dateline_cross = lon_min > lon_max
    if dateline_cross:
        lon_span = (lon_max + 360.0) - lon_min
    else:
        lon_span = lon_max - lon_min

    # 3. 极点附近风险
    polar_risk = max(abs(lat_min), abs(lat_max)) > 85.0

    # 4. 球面面积与周长
    phi_min = math.radians(lat_min)
    phi_max = math.radians(lat_max)
    dlam = math.radians(lon_span)
    area = R * R * dlam * abs(math.sin(phi_max) - math.sin(phi_min))

    l_lat_max = R * dlam * math.cos(phi_max)
    l_lat_min = R * dlam * math.cos(phi_min)
    l_lon = R * abs(phi_max - phi_min)
    perimeter = 2 * (l_lat_max + l_lat_min) + 2 * l_lon

    # 5. 四顶点(顺时针:西北→东北→东南→西南)
    vertices = [
        (normalize_lon(lon_min), lat_max),  # P1 西北
        (normalize_lon(lon_max), lat_max),  # P2 东北
        (normalize_lon(lon_max), lat_min),  # P3 东南
        (normalize_lon(lon_min), lat_min),  # P4 西南
    ]

    center_lon = normalize_lon(lon_min + lon_span / 2.0)
    center_lat = (lat_min + lat_max) / 2.0

    return {
        "valid": True,
        "bounds": {"lon_min": lon_min, "lon_max": lon_max,
                   "lat_min": lat_min, "lat_max": lat_max},
        "lon_span_deg": lon_span,
        "vertices": vertices,
        "center": (center_lon, center_lat),
        "area_km2": round(area, 3),
        "perimeter_km": round(perimeter, 3),
        "flags": {"dateline_cross": dateline_cross, "polar_risk": polar_risk},
    }

# 示例:普通区域
r1 = build_rect_region(120.0, 125.0, 10.0, 15.0)
print(r1["area_km2"], r1["perimeter_km"], r1["flags"])

# 示例:跨日期变更线
r2 = build_rect_region(170.0, -170.0, -5.0, 5.0)
print(r2["lon_span_deg"], r2["flags"]["dateline_cross"])

# 示例:极点附近
r3 = build_rect_region(0.0, 30.0, 86.0, 88.0)
print(r3["flags"]["polar_risk"])

结果判读与通过条件

校验项判定条件处理方式
纬度顺序lat_min < lat_max不满足则 valid=false,拒绝进入规划
经度范围边界值在 [−180, 180] 内越界则拒绝,或先归一化再重试
日期变更线lon_min > lon_max置 dateline_cross=true,经度跨度按 +360 修正
极点附近max(|lat_min|,|lat_max|) > 85°置 polar_risk=true,提示规划器缩小航向步长
面积/周长均为正值且量级合理作为后续覆盖路径长度估算的输入

通过条件:valid=true,四顶点按顺时针闭合,area_km2 与 perimeter_km 为正,且 flags 中异常标记与输入实际情况一致。例如输入 (170, −170, −5, 5) 时,lon_span_deg 应为 20°,dateline_cross 为 true;输入 (0, 30, 86, 88) 时,polar_risk 应为 true。

顶点顺序统一采用“西北→东北→东南→西南”的顺时针约定,与后续多边形规范化案例的输入格式保持一致,避免下游再做一次顺序修正。
不要用平面近似 Δlon × Δlat × 111.32² 直接算面积:在中高纬度会明显偏大,且跨日期变更线时符号与宽度都会出错。