using KYFramework; using Model; using Newtonsoft.Json; using Org.BouncyCastle.Utilities; using SimulationCommon; using SimulationServer.Utils; using Define = SimulationServer.Utils.Define; namespace SimulationServer; public class AircraftKTKS : AircraftEntity { public string NextMissionId; // 下一个任务ID public MissionEndPoint missionEndPoint = new MissionEndPoint(); public int LandingPersonnel; //personCount public MHRescueMission mhRescueMission; public int landingPoint = 0; // 任务文件获取 public MissionPoint missionpoint = new MissionPoint(); public KTKSTask taskContent; // 创建任务里需要赋值!!! int Days; int Hour; public TaskParameter taskParameter; public bool IsOver; public bool Success; public RescueDemandInfo rescueDemandInfo; public bool isReadNC; Text_readNC text_ReadNC; public override void End() { TotalFuelConsumption = TurningPoints[0].RemainingFuel - TurningPoints[^1].RemainingFuel; } public override void Reset() { base.Reset(); IsOver = false; Success = false; TotalTime = 0; } public override void Start() { // FlightPlanEditor.targetpoint = 空投点 FlightPlanEditor.missionpoint.MissionPointLatitude = rescueDemandInfo.TargetPointLatitude; FlightPlanEditor.missionpoint.MissionPointLongitude = rescueDemandInfo.TargetPointLongitude; FlightPlanEditor.missionpoint.MissionPointHeight = rescueDemandInfo.TargetPointHeight; //Console.WriteLine("MissionPointLatitude:" + FlightPlanEditor.missionpoint.MissionPointLatitude); FXJHGenerate.FromStartToMission(FlightPlanEditor, ref TurningPoints);//生成从起点到任务段起点的航路点 int TransportNumber = (int)Math.Ceiling(LandingPersonnel / FlightPlanEditor.aircraftparameter.MaxPassengerNumber); int j = 0; //FlightPlanEditor.missionpoint.MissionPointLatitude = FlightPlanEditor.targetpoint[0].TargetPointLatitude; //FlightPlanEditor.missionpoint.MissionPointLongitude = FlightPlanEditor.targetpoint[0].TargetPointLongitude; //FlightPlanEditor.missionpoint.MissionPointHeight = FlightPlanEditor.targetpoint[0].TargetPointHeight; FXJHGenerate.KouTouKouSong(FlightPlanEditor, ref TurningPoints); double alpha = CalculateEastBaseAngle(TurningPoints[0].TurningPointLatitude, TurningPoints[0].TurningPointLongitude, TurningPoints[2].TurningPointLatitude, TurningPoints[2].TurningPointLongitude); //FXJHGenerate.CalculateTrueHeading(FlightPlanEditor, ref TurningPoints); // FXJHGenerate.InitializeVelocities(FlightPlanEditor, TurningPoints, ref Velocitys); // FXJHGenerate.InitializeFuelConsumptions(FlightPlanEditor, TurningPoints,ref FuelConsumptions); //FXJHGenerate.FromMissionToEnd(FlightPlanEditor, missionEndPoint, ref TurningPoints); //FXJHGenerate.FXJHTPDiedai(FlightPlanEditor, ref TurningPoints, Velocitys, FuelConsumptions); // 更新了 计算油耗的方法 int Year = Convert.ToInt32(taskContent.missionInformation.StartDate.Split("年")[0]); int Month = Convert.ToInt32(taskContent.missionInformation.StartDate.Split("年")[1].Split("月")[0]); int Day = Convert.ToInt32(taskContent.missionInformation.StartDate.Split("年")[1].Split("月")[1].Split("日")[0]); Hour = Convert.ToInt32(taskContent.missionInformation.StartTime.Split("时")[0]); Days = GetDaysInYear(Year, Month, Day); if (!isReadNC) { text_ReadNC = new Text_readNC(); text_ReadNC.initlatitudes = rescueDemandInfo.TargetPointLatitude; text_ReadNC.initlongitudes = rescueDemandInfo.TargetPointLongitude; bool isSuccess = false; while (!isSuccess) { isSuccess = text_ReadNC.GetNCData(); } isReadNC = true; } var nCread = text_ReadNC.windNCread; double[] windVelocity = GetWindVelocityFromAPI(nCread, rescueDemandInfo.TargetPointLatitude, rescueDemandInfo.TargetPointLongitude, text_ReadNC.latitudes, text_ReadNC.longitudes, Days, Hour); var windSpeed = Math.Sqrt(windVelocity[0] * windVelocity[0] + windVelocity[1] * windVelocity[1]); var theta = Math.Asin(windVelocity[0] / windSpeed); List KTiniposition = new List(); List KTresultPostion = new List(); double KTheight; if (taskParameter.isParachute) //空投空送任务文件读取 { KTheight = 200; // 空投迎风面积 = 1.5 空投空送任务文件读取 50 = 空投重量 空投空送任务文件读取 KTiniposition = getPositionWithUmbrella(FlightPlanEditor.missionpoint.MissionPointLongitude, FlightPlanEditor.missionpoint.MissionPointLatitude, KTheight, windSpeed, theta, taskParameter.airdropWindArea, taskParameter.airdropWeight); double inix = Mokatuo_lon(KTiniposition[1]); double iniy = Mokatuo_lat(KTiniposition[0]); double resultX = inix + 33 * Math.Cos(alpha) * KTiniposition[2] / 1000; double resultY = iniy + 33 * Math.Sin(alpha) * KTiniposition[2] / 1000; KTresultPostion.Add(ReMokatuo_lat(resultY)); KTresultPostion.Add(ReMokatuo_lon(resultX)); } else { KTheight = 20; KTiniposition = getPositionWithoutUmbrella(FlightPlanEditor.missionpoint.MissionPointLongitude, FlightPlanEditor.missionpoint.MissionPointLatitude, KTheight, windSpeed, 22, alpha, theta); double inix = Mokatuo_lon(KTiniposition[1]); double iniy = Mokatuo_lat(KTiniposition[0]); double resultX = inix + 22 * Math.Cos(alpha) * KTiniposition[2] / 1000; double resultY = iniy + 22 * Math.Sin(alpha) * KTiniposition[2] / 1000; KTresultPostion.Add(ReMokatuo_lat(resultY)); KTresultPostion.Add(ReMokatuo_lon(resultX)); } TurningPoints.RemoveAt(2); if(taskParameter.airdropWay == "带速空投") { FlightPlanEditor.missionpoint.MissionPointLatitude = KTiniposition[0]; FlightPlanEditor.missionpoint.MissionPointLongitude = KTiniposition[1]; FlightPlanEditor.missionpoint.MissionPointHeight = KTheight; missionpoint.MissionPointLatitude = KTresultPostion[0]; missionpoint.MissionPointLongitude = KTresultPostion[1]; missionpoint.MissionPointHeight = KTheight; missionEndPoint.MissionEndPointLatitude = KTresultPostion[0]; missionEndPoint.MissionEndPointLongitude = KTresultPostion[1]; missionEndPoint.MissionEndPointHeight = KTheight; } else if(taskParameter.airdropWay == "悬停空投") { FlightPlanEditor.missionpoint.MissionPointLatitude = KTiniposition[0]; FlightPlanEditor.missionpoint.MissionPointLongitude = KTiniposition[1]; FlightPlanEditor.missionpoint.MissionPointHeight = KTheight; missionpoint.MissionPointLatitude = KTiniposition[0]; missionpoint.MissionPointLongitude = KTiniposition[1]; missionpoint.MissionPointHeight = KTheight; missionEndPoint.MissionEndPointLatitude = KTiniposition[0]; missionEndPoint.MissionEndPointLongitude = KTiniposition[1]; missionEndPoint.MissionEndPointHeight = KTheight; } FXJHGenerate.KouTouKouSong(FlightPlanEditor, ref TurningPoints); FXJHGenerate.KouTouKouSong1(missionpoint, ref TurningPoints); TurningPoints[2].SegmentFlightTime = KTiniposition[2]; FXJHGenerate.FromMissionToEnd(FlightPlanEditor, missionEndPoint, ref TurningPoints); FXJHGenerate.FXJHTPDiedai(FlightPlanEditor, ref TurningPoints, Velocitys, FuelConsumptions); // 更新了 计算油耗的方法 for (int i = 0; i < TurningPoints.Count; i++) // 总飞行时间 { TotalTime += TurningPoints[i].SegmentFlightTime; // 总时间 //仿真轮次1 数值1 } Console.WriteLine("TotalTime:" + TotalTime); IsOver = true; //Success = true; //需要判断 End(); } //private double GetDistance(double lon1, double lon2, double lat1, double lat2) //{ // double R = 6371; // 地球的半径(公里) // double dLat = (lat2 - lat1) * Math.PI / 180.0; // double dLon = (lon2 - lon1) * Math.PI / 180.0; // double a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) + // Math.Cos(lat1 * Math.PI / 180.0) * Math.Cos(lat2 * Math.PI / 180.0) * // Math.Sin(dLon / 2) * Math.Sin(dLon / 2); // double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a)); // double distance = R * c; // return distance; //} public override void Update(double time) { } // --接口 // --输入 // -- // 1)遇险人员位置经度(空投拟落点位置经度) // --longitude(double) // 2)遇险人员位置维度(空投拟落点位置维度) //--latitude(double) // 3)释放空投时飞机的高度(m) //--altitude(double) // 4)飞行器空投速度(m/s) //--windspeed(double) // 5)飞行速度与维度夹角(度)(应该可以在飞机的运动学参数读出来)__________东向为0 //--alpha(double)__________先定值,后续与子涵对 // 6)风速与维度夹角(度)(环境参数)__________东向为0 //--theta(double)__________改成风向 // 7)风速(m/s) //--windspeed(double) // 8)空投重量(kg) //--m(double) // 9)空投迎风面积(m2)(空投侧面积即可) //--s(double) // 10)空投距离多远算做成功 //--l(m)(double) // -- // --输出 // -- // 1)可以空投区域的中心点经纬度 //--result(List) // 2)空投距离多远算做成功(m) //--l(double) // -- 三个输出变量构一个圆形区域 // -- //返回高度、速度、空投任务段时间 public static double[] GetWindVelocityFromAPI(NCread windNCread, double latitude, double longitude, int latitudes, int longitudes, int days, int hour) { float[] longitudeArray = windNCread.longitudeArray;//经度一维数组来源自文件'Text_readNC.cs' float[] latitudeArray = windNCread.latitudeArray;//纬度一维数组来源自文件'Text_readNC.cs' float[][][] u10Array = windNCread.u10Array;//风的10米U(向东)分量三维数组来源自文件'Text_readNC.cs' float[][][] v10Array = windNCread.v10Array;//风的10米V(向北)分量三维数组来源自文件'Text_readNC.cs' int longitudeNum = 0; int latitudeNum = 0; int temptimeNum = 0; //定义NC文件中读取不到的坐标点海洋数据信息(后续可采用插值法等) //经度连续化 for (int i = 0; i < longitudes - 1; i++) { if (longitude >= longitudeArray[i] && longitude < longitudeArray[i + 1]) { longitude = longitudeArray[i]; longitudeNum = i; } } //纬度连续化 for (int i = 0; i < latitudes - 1; i++) { if (latitude >= latitudeArray[i] && latitude < latitudeArray[i + 1]) { latitude = latitudeArray[i]; latitudeNum = i; } } temptimeNum += (days - 1) * 24 + hour - 1; double windX = (double)u10Array[temptimeNum][latitudeNum][longitudeNum]; double windY = (double)v10Array[temptimeNum][latitudeNum][longitudeNum]; return new double[] { windX, windY }; } // --主要方法 // --墨卡托投影函 public double Mokatuo_lat(double lat) { double R = 6378.137; double y = R * Math.Log(Math.Tan((lat + 90) * Math.PI / 360)); return y; } public double Mokatuo_lon(double lon) { double R = 6378.137; double x = (lon * Math.PI * R) / 180; return x; } // --反墨卡托投影函数 public double ReMokatuo_lat(double y) { double R = 6378.137; double lat = (2 * Math.Atan(Math.Exp(y / R)) - Math.PI / 2) * 180 / Math.PI; return lat; } public double ReMokatuo_lon(double x) { double R = 6378.137; double lon = x * 180 / (Math.PI * R); return lon; } // --不开伞空投计算函数 //速度80km/h;高度20m public List getPositionWithoutUmbrella(double longitude, double latitude, double altitude, double windspeed, double velocity, double alpha, double theta) { double g = 9.8; double time = Math.Sqrt(2 * altitude / g); double x = Mokatuo_lon(longitude); double y = Mokatuo_lat(latitude); double vx = velocity * Math.Cos(alpha) + windspeed * Math.Cos(theta); double vy = velocity * Math.Sin(alpha) + windspeed * Math.Sin(theta); double y_new = y + vy * time / 1000; double x_new = x + vx * time / 1000; double lat = ReMokatuo_lat(y_new); double lon = ReMokatuo_lon(x_new); List result = new List() {lat, lon,time}; return result; //投放空投的位置 } // --开伞空投计算函数 //速度120km/h;高度200m public List getPositionWithUmbrella(double longitude, double latitude, double altitude, double windspeed, double theta, double s, double m) { double g = 9.8; double k = 3.824 * s; double vz = Math.Sqrt(m * g / k); double time = altitude / vz; double x = Mokatuo_lon(longitude); double y = Mokatuo_lat(latitude); double y_new = y + windspeed * Math.Sin(theta) * time / 1000; double x_new = x + windspeed * Math.Cos(theta) * time / 1000; double lat = ReMokatuo_lat(y_new); double lon = ReMokatuo_lon(x_new); List result = new List() {lat, lon,time}; Console.WriteLine(y_new); Console.WriteLine(y); return result; //投放空投的位置 } public static int GetDaysInYear(int year, int month, int day) { int[] daysInMonths = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; if (IsLeapYear(year)) { daysInMonths[1] = 29; } int days = day; for (int i = 0; i < month - 1; i++) { days += daysInMonths[i]; } return days; } public static bool IsLeapYear(int year) { return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); } public static double CalculateEastBaseAngle(double lat1, double lon1, double lat2, double lon2) { // 转换为弧度 double lat1Rad = lat1 * Math.PI / 180; double lon1Rad = lon1 * Math.PI / 180; double lat2Rad = lat2 * Math.PI / 180; double lon2Rad = lon2 * Math.PI / 180; double deltaLon = lon2Rad - lon1Rad; // 计算真航向角 double x = Math.Sin(deltaLon) * Math.Cos(lat2Rad); double y = Math.Cos(lat1Rad) * Math.Sin(lat2Rad) - Math.Sin(lat1Rad) * Math.Cos(lat2Rad) * Math.Cos(deltaLon); double headingRad = Math.Atan2(x, y); double headingDeg = headingRad * 180 / Math.PI; // 标准化真航向角(以正北为基准) headingDeg = (headingDeg + 360) % 360; // 转换为以正东为基准的角度,逆时针方向 double eastBaseAngle = (90 - headingDeg) % 360; if (eastBaseAngle < 0) { eastBaseAngle += 360; } return eastBaseAngle; } } [ObjectSystem] public class AircraftKTKSAwakeSystem : AwakeSystem { public override void Awake(AircraftKTKS self, FlightPlanEditor flightPlanEditor) { self.FlightPlanEditor = flightPlanEditor; self.Awake(); //self.Reset(); } }