Files
VDES_Backend/code/system/apis/vdes/header.py
2026-07-13 15:37:05 +08:00

151 lines
5.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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