151 lines
5.9 KiB
Python
151 lines
5.9 KiB
Python
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 |