import random import math from ninja import Router from django.utils import timezone from datetime import timedelta from system.models import GpsStatus, ShipLatestStatus, MessageFlag from fuadmin.settings import OWN_SHIP_MMSI router = Router() def haversine(lat1, lon1, lat2, lon2): """计算两点间的大圆距离(公里)""" R = 6371 # 地球半径(公里) # 将角度转换为弧度 lat1, lon1, lat2, lon2 = map(math.radians, [lat1, lon1, lat2, lon2]) # 差值 dlat = lat2 - lat1 dlon = lon2 - lon1 # Haversine公式 a = math.sin(dlat/2)**2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon/2)**2 c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a)) return R * c def calculate_relative_bearing(own_lat, own_lon, own_course, target_lat, target_lon): """ 计算目标点相对本船航向的方向角(相对方位,单位°,0~360,顺时针) """ d_lon = math.radians(target_lon - own_lon) lat1 = math.radians(own_lat) lat2 = math.radians(target_lat) x = math.sin(d_lon) * math.cos(lat2) y = math.cos(lat1)*math.sin(lat2) - math.sin(lat1)*math.cos(lat2)*math.cos(d_lon) initial_bearing = math.atan2(x, y) initial_bearing_deg = (math.degrees(initial_bearing) + 360) % 360 # 转换为 0~360 度 # 相对航向(目标相对于本船正前的角度) relative_bearing = (initial_bearing_deg - own_course + 360) % 360 return relative_bearing @router.get("/header") def get_header_info(request): # 固定本船MMSI ownship_mmsi = OWN_SHIP_MMSI # current_time = datetime.now() # current_date = current_time.strftime('%Y-%m-%d') # current_time_str = current_time.strftime('%H:%M') # # 检查是否是第一次调用,如果是则初始化位置 # if not hasattr(get_header_info, 'ship_data'): # # 初始位置 (30.9918, 122.2788) # get_header_info.ship_data = { # 'mmsi': ownship_mmsi, # 'latitude': 30.9918, # 'longitude': 122.2788, # 'speed': 12.0, # 'course': 45, # 'date': current_date, # 'time': current_time_str # } # else: # # 更新位置和航向 # get_header_info.ship_data['latitude'] = round(get_header_info.ship_data['latitude'] + 0.001, 4) # get_header_info.ship_data['longitude'] = round(get_header_info.ship_data['longitude'] + 0.001, 4) # get_header_info.ship_data['course'] = round((get_header_info.ship_data['course'] + 5) % 360, 1) # get_header_info.ship_data['date'] = current_date # get_header_info.ship_data['time'] = current_time_str # # 将数据保存到GpsStatus模型 # GpsStatus.objects.create( # utc_time=current_time, # longitude=get_header_info.ship_data['longitude'], # latitude=get_header_info.ship_data['latitude'], # altitude=0.0, # 固定值 # used_satellites=10, # 固定值 # gps_satellites=6, # 固定值 # beidou_satellites=4, # 固定值 # gps_status=1, # 固定值,1表示正常 # fix_mode=3, # 固定值,3表示3D定位 # hdop=1.2, # 固定值 # speed=get_header_info.ship_data['speed'], # direction=get_header_info.ship_data['course'] # ) #查询最新经纬度数据 latest_gps = GpsStatus.objects.order_by('-utc_time').first() # 计算 10 分钟前的时间,基于 GpsStatus 中的时间 ten_minutes_ago = latest_gps.utc_time - timedelta(minutes=10) # 筛选出 10 分钟内的船只记录 recent_ships = ShipLatestStatus.objects.filter(timestamp__gte=ten_minutes_ago) closest_ship = None min_distance_km = float('inf') for ship in recent_ships: # 计算本船与当前船只的距离(公里) distance_km = haversine(latest_gps.latitude, latest_gps.longitude, ship.latitude, ship.longitude) if distance_km < min_distance_km: min_distance_km = distance_km closest_ship = ship # 判断是否小于 5 海里(1 海里 = 1.852 公里) warning_message = '' # min_distance_km = random.randint(1, 20) print(min_distance_km) if 3 * 1.852 < min_distance_km < 5 * 1.852: warning_message = '注意,5海里范围内有其他船只' print(warning_message) elif min_distance_km <= 3 * 1.852: relative_bearing = calculate_relative_bearing( latest_gps.latitude, latest_gps.longitude, latest_gps.direction, # 本船航向 closest_ship.latitude, closest_ship.longitude ) warning_message = f'警告:有船靠近,相对方位 {relative_bearing:.1f}°,相距 {min_distance_km / 1.852:.2f} 海里, 速度{closest_ship.speed}节' else: warning_message = '保持正常航行' flag = MessageFlag.objects.first() has_message = flag.has_new_message if has_message: flag.has_new_message = False flag.save() return { 'mmsi': ownship_mmsi, # 固定本船MMSI 'latitude': latest_gps.latitude, 'longitude': latest_gps.longitude, 'speed': latest_gps.speed, 'course': latest_gps.direction, 'date': latest_gps.utc_time.strftime('%Y-%m-%d'), 'time': latest_gps.utc_time.strftime('%H:%M'), "satelliteCount": random.randint(0, 12), "messageCount": 12, "reminderCount": random.randint(0, 20), "alertCount": random.randint(0, 15), "approachingCount": random.randint(0, 5), "trackStatus": False, "gpsSignal": round(random.uniform(0, 5), 1), "beidouSignal": round(random.uniform(0, 5), 1), "vdesSignal": round(random.uniform(0, 5), 1), "warning_message": warning_message, "is_receive_vdes_data": has_message } # return get_header_info.ship_data