|
@@ -0,0 +1,336 @@
|
|
|
+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 override void End()
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public override void Reset()
|
|
|
+ {
|
|
|
+ base.Reset();
|
|
|
+ }
|
|
|
+ public override void Start()
|
|
|
+ {
|
|
|
+ // FlightPlanEditor.targetpoint = 空投点
|
|
|
+
|
|
|
+ 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);
|
|
|
+ Text_readNC text_ReadNC = new Text_readNC();
|
|
|
+ text_ReadNC.GetNCData();
|
|
|
+ var nCread = text_ReadNC.windNCread;
|
|
|
+
|
|
|
+ double[] windVelocity = GetWindVelocityFromAPI(nCread, FlightPlanEditor.targetpoint[0].TargetPointLatitude, FlightPlanEditor.targetpoint[0].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<double> KTiniposition = new List<double>();
|
|
|
+ List<double> KTresultPostion = new List<double>();
|
|
|
+
|
|
|
+ double KTheight;
|
|
|
+ if("开伞空投" == "True") //空投空送任务文件读取
|
|
|
+ {
|
|
|
+ KTheight = 200;
|
|
|
+ // 空投迎风面积 = 1.5 空投空送任务文件读取 50 = 空投重量 空投空送任务文件读取
|
|
|
+ KTiniposition = getPositionWithUmbrella(FlightPlanEditor.missionpoint.MissionPointLongitude, FlightPlanEditor.missionpoint.MissionPointLatitude, KTheight, windSpeed, theta, 1.5, 50);
|
|
|
+ double inix = Mokatuo_lon(KTiniposition[1]);
|
|
|
+ double iniy = Mokatuo_lat(KTiniposition[0]);
|
|
|
+
|
|
|
+ double resultX = inix + 33 * Math.Cos(alpha) * KTiniposition[2];
|
|
|
+ double resultY = iniy + 33 * Math.Sin(alpha) * KTiniposition[2];
|
|
|
+
|
|
|
+ KTresultPostion[0] = ReMokatuo_lat(resultY);
|
|
|
+ KTresultPostion[1] = ReMokatuo_lon(resultX);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ KTheight = 20;
|
|
|
+ KTiniposition = getPositionWithoutUmbrella(FlightPlanEditor.missionpoint.MissionPointLongitude, FlightPlanEditor.missionpoint.MissionPointLatitude, KTheight, windSpeed, 22, alpha, theta);
|
|
|
+ }
|
|
|
+
|
|
|
+ TurningPoints.RemoveAt(2);
|
|
|
+ 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;
|
|
|
+
|
|
|
+ FXJHGenerate.KouTouKouSong(FlightPlanEditor, ref TurningPoints);
|
|
|
+ FXJHGenerate.KouTouKouSong1(missionpoint, ref TurningPoints);
|
|
|
+
|
|
|
+ missionEndPoint.MissionEndPointLatitude = KTresultPostion[0];
|
|
|
+ missionEndPoint.MissionEndPointLongitude = KTresultPostion[1];
|
|
|
+ missionEndPoint.MissionEndPointHeight = KTheight;
|
|
|
+
|
|
|
+ FXJHGenerate.FromMissionToEnd(FlightPlanEditor, missionEndPoint, ref TurningPoints);
|
|
|
+ FXJHGenerate.FXJHTPDiedai(FlightPlanEditor, ref TurningPoints, Velocitys, FuelConsumptions); // 更新了 计算油耗的方法
|
|
|
+ }
|
|
|
+
|
|
|
+ //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<double>)
|
|
|
+ // 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<double> 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<double> result = new List<double>()
|
|
|
+ {lat, lon,time};
|
|
|
+ return result; //投放空投的位置
|
|
|
+ }
|
|
|
+ // --开伞空投计算函数
|
|
|
+ //速度120km/h;高度200m
|
|
|
+ public List<double> 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<double> result = new List<double>()
|
|
|
+ {lat, lon};
|
|
|
+ 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<AircraftKTKS, FlightPlanEditor>
|
|
|
+{
|
|
|
+ public override void Awake(AircraftKTKS self, FlightPlanEditor flightPlanEditor)
|
|
|
+ {
|
|
|
+ self.FlightPlanEditor = flightPlanEditor;
|
|
|
+ self.Awake();
|
|
|
+ self.Reset();
|
|
|
+ }
|
|
|
+}
|