/// <summary> /// приведение ряда к условиям плоской местности /// </summary> /// <param name="ms_range">ряд</param> /// <param name="expectancy">повторяемости направлений ветра</param> /// <param name="ms_classes">классы открытости МС</param> /// <param name="water_type">расстояние до водной поверхности</param> /// <returns></returns> public static RawRange ToFlatTerrain(RawRange ms_range, StatisticalRange <WindDirections8> expectancy, Dictionary <WindDirections8, double> ms_classes, WaterDistanceType water_type) { //1. найти Кмс //2. пересчитать ряд RawRange result = new RawRange(); double K0 = (int)water_type; //средневзвешенный коэффициент открытости метеостанции double Kms = 0; foreach (WindDirections8 dir in WindDirections8.N.GetEnumItems()) { if (dir != WindDirections8.Calm && dir != WindDirections8.Undefined && dir != WindDirections8.Variable) { Kms += expectancy[dir] * ms_classes[dir]; } } double k0 = K0 / Kms; result.BeginChange(); foreach (RawItem item in ms_range) { RawItem ni = item.Clone(); ni.Speed = item.Speed * k0; result.Add(ni); } result.EndChange(); return(result); }
/// <summary> /// поднять ряд на высоту с заданными настройками /// </summary> /// <param name="Range">поднимаемый ряд</param> /// <param name="param">настройки</param> /// <param name="actionPercent">действие при изменении процента выполнения</param> /// <param name="actionAfter">действие по окончании выполнения</param> public async static Task <RawRange> ProcessRange(RawRange Range, ElevatorParameters param, Action <int> actionPercent = null, Action <RawRange, SuitAMSResultItem> actionAfter = null) { //найти подходящую АМС //получить из неё параметры m по месяцам //поднять ряд Range на высоту //выбор варианта расчета m: через БД АМС или введенный вручную Dictionary <Months, double> coeffs = null; switch (param.HellmanCoefficientSource) { case HellmanCoefficientSource.AMSAnalog: coeffs = getAMSAnalogCoefficients(param.SelectedAMS.AMS, Range); break; case HellmanCoefficientSource.CustomMonths: coeffs = param.CustomMCoefficientMonths; break; case HellmanCoefficientSource.CustomOne: coeffs = new Dictionary <Months, double>(); for (int i = 1; i <= 12; i++) { coeffs.Add((Months)i, param.CustomMCoefficient); } break; default: throw new Exception("Этот источник данных не реализован"); } coeffs = coeffs ?? throw new ArgumentException("Недопустимые настройки, коэффициенты пересчета на высоту не получены"); //поднять ряд с учетом m по месяцам RawRange res = new RawRange(); res.Position = Range.Position; res.Height = param.ToHeight; res.BeginChange(); return(await Task.Run(() => { double c = 0; foreach (RawItem item in Range) { c++; if (Math.IEEERemainder(c, 100) == 0 && actionPercent != null) { actionPercent.Invoke((int)((c / Range.Count) * 100)); } Months month = (Months)item.Date.Month; double m = coeffs[month]; double oldV = item.Speed; double newV = oldV *Math.Pow(param.ToHeight / param.FromHeight, m); RawItem ni = item.Clone(); ni.Speed = newV; res.Add(ni); } res.EndChange(); if (actionAfter != null) { actionAfter.Invoke(res, param.SelectedAMS); } return res; })); }
/// <summary> /// Загрузка ряда из файла xlsx /// </summary> /// <param name="fileName">адрес файла</param> /// <returns></returns> public override RawRange LoadRange(string fileName) { FileInfo fi = new FileInfo(fileName); using (ExcelPackage excelPackage = new ExcelPackage(fi)) { if (excelPackage.Workbook.Worksheets.Count == 0) { return(null); } ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets[0]; if (worksheet.Cells[3, 1].Value == null) { return(null); } string title = worksheet.Cells[1, 1].Value.ToString(); string coordinates = worksheet.Cells[2, 1].Value.ToString(); string name = worksheet.Cells[3, 1].Value.ToString(); string height = worksheet.Cells[2, 2].Value != null ? worksheet.Cells[2, 2].Value.ToString() : "не число"; if (!double.TryParse(height, out double rangeHeight)) { rangeHeight = double.NaN; } RawRange res = new RawRange() { Name = name }; //чтение координат файла string regex = @"^\d+[\.\,].\d*\s+\d+[\.\,].\d*$"; bool isMatch = new Regex(regex).IsMatch(coordinates); PointLatLng coord; if (isMatch) { string[] s = coordinates.Split(' '); double lat = double.Parse(s[0].Trim().Replace('.', Constants.DecimalSeparator)); double lon = double.Parse(s[1].Trim().Replace('.', Constants.DecimalSeparator)); coord = new PointLatLng(lat, lon); } else { coord = PointLatLng.Empty; } res.Position = coord; res.BeginChange(); var arr = worksheet.Cells; for (int i = 5; i <= worksheet.Dimension.Rows; i++) { DateTime dt = getDateTime(arr[i, 1]); double temp = getDouble(arr[i, 2]); double spd = getDouble(arr[i, 5]); double press = getDouble(arr[i, 6]); double wet = getDouble(arr[i, 3]); double dirs = getDouble(arr[i, 4]); try { res.Add(new RawItem() { Date = dt, Direction = dirs, Speed = spd, Temperature = temp, Wetness = wet, Pressure = press }); } catch (Exception) { continue; } } //поиск информации о МС RP5MeteostationInfo meteostation = null; int start = title.IndexOf("ID=") + "ID=".Length; string id_s = title.Substring(start); if (id_s.ToLower() != "nasa" && id_s.ToLower() != "undefined") { meteostation = Vars.RP5Meteostations.GetByID(id_s); } res.Meteostation = meteostation; res.Height = rangeHeight; res.EndChange(); return(res); } }
/// <summary> /// Пытается импортировать файл на основе заданных настроек. При ошибке выбрасывает исключение WindEnergyException с информацией или ArgumentException при недопустимых настройках /// </summary> /// <returns></returns> /// <param name="count">количество считываемых строк, начиная со StartLine</param> public RawRange Import(long count = long.MaxValue) { CheckParameters(); //проверка параметров //Импорт данных string data = GetText(count); RawRange res = new RawRange(); res.BeginChange(); string[] lines = data.Split('\r'); int line_i = 0; foreach (string line in lines) { line_i++; string[] arr = new Regex("w*" + Delimeter + "w*").Split(line.Replace("\n", "")); if (arr.Length <= 1) { continue; } List <ImportFields> fields = this.Columns.Keys.ToList(); RawItem item = new RawItem(); foreach (ImportFields field in fields) { int index = Columns[field] - 1; string value = arr[index]; if (Trimmers != null && Trimmers.Length > 0) { value = value.Trim(Trimmers); } try { switch (field) { case ImportFields.Date: item.Date = DateTime.Parse(value); break; case ImportFields.Direction: switch (DirectionUnit) { case DirectionUnits.Degrees: item.Direction = double.Parse(value.Replace('.', Constants.DecimalSeparator)); break; case DirectionUnits.TextRP5: item.DirectionRhumb = RP5ru.GetWindDirectionFromString(value); break; case DirectionUnits.None: throw new ArgumentException("Не заданы единицы измерения для направления"); default: throw new WindEnergyException("Эта единица измерений не реализована"); } break; case ImportFields.Pressure: switch (PressureUnit) { case PressureUnits.KPa: item.Pressure = double.Parse(value.Replace('.', Constants.DecimalSeparator)) * Constants.MMHGART_IN_1KPA; //перевод в мм рт. ст. break; case PressureUnits.mmHgArt: item.Pressure = double.Parse(value.Replace('.', Constants.DecimalSeparator)); break; case PressureUnits.None: throw new ArgumentException("Не заданы единицы измерения для давления"); default: throw new WindEnergyException("Эта единица измерений не реализована"); } break; case ImportFields.Wetness: switch (WetnessUnit) { case WetnessUnits.Percents: item.Wetness = double.Parse(value.Replace('.', Constants.DecimalSeparator)); break; case WetnessUnits.Parts: item.Wetness = double.Parse(value.Replace('.', Constants.DecimalSeparator)) * 100d; //перевод в % break; case WetnessUnits.None: throw new ArgumentException("Не заданы единицы измерения для влажности"); default: throw new WindEnergyException("Эта единица измерений не реализована"); } break; case ImportFields.Temperature: item.Temperature = double.Parse(value.Replace('.', Constants.DecimalSeparator)); break; case ImportFields.Speed: item.Speed = double.Parse(value.Replace('.', Constants.DecimalSeparator)); break; default: throw new WindEnergyException("Этот параметр не реализован"); } } catch (Exception ex) { throw new WindEnergyException($"Не удалось распознать строку \"{value}\" как значение поля {field.Description()} в строке {line_i}", ex.Message); } } res.Add(item); } if ((bool)BindNearestMS) { res.Meteostation = Vars.RP5Meteostations.GetNearestMS(this.Coordinates); } res.Position = this.Coordinates; res.Name = Path.GetFileNameWithoutExtension(this.FilePath); res.EndChange(); res.PerformRefreshQuality(); return(res); }
/// <summary> /// поднять ряд на высоту с заданными настройками /// </summary> /// <param name="Range">поднимаемый ряд</param> /// <param name="param">настройки</param> /// <param name="actionPercent">действие при изменении процента выполнения</param> /// <param name="actionAfter">действие по окончании выполнения</param> public static void ProcessRange(RawRange Range, TerrainParameters param, Action <int> actionPercent, Action <RawRange, FlugerMeteostationInfo> actionAfter) { RawRange result = new RawRange(); result.Position = param.PointCoordinates; result.Name = $"Ряд в точке {param.PointCoordinates.ToString(3)}"; result.BeginChange(); switch (param.TerrainType) { case TerrainType.Macro: Dictionary <WindDirections8, double> k0 = getTerrainMacroK0(param.MSClasses, param.PointClasses); //получаем коэффициенты для плоского рельефа //пересчет всех скоростей ряда double c = 0; foreach (var item in Range) { WindDirections8 wd8 = item.DirectionRhumb8; if (wd8 == WindDirections8.Calm || wd8 == WindDirections8.Undefined || wd8 == WindDirections8.Variable) { continue; } double nspeed = item.Speed * k0[wd8]; //для направления в этой точке пересчитываем скорости RawItem nitem = item.Clone(); nitem.Speed = nspeed; result.Add(nitem); c++; if (Math.IEEERemainder(c, 100) == 0 && actionPercent != null) { actionPercent((int)((c / Range.Count) * 100)); } } break; case TerrainType.Meso: //мезоклиматический коэффициент double Km = (param.MesoclimateCoefficient.Value.From + param.MesoclimateCoefficient.Value.To) / 2d; //среднее внутри диапазона //выбор преобладающих направлений ветра List <WindDirections8> dominants = GetRhumbsDominants(Range); //пересчет ряда только для преобладающих направлений foreach (RawItem item in Range) { RawItem ni = item.Clone(); ni.Speed = dominants.Contains(ni.DirectionRhumb8) ? ni.Speed * Km : ni.Speed; result.Add(ni); } break; case TerrainType.Micro: //выбор преобладающих направлений ветра List <WindDirections8> directs = GetRhumbsDominants(Range); //пересчет ряда только для преобладающих направлений foreach (RawItem item in Range) { double Kmk = selectMicroclimateCoefficient(item.Speed, param.MicroclimateCoefficient, param.AtmosphereStratification); RawItem ni = item.Clone(); ni.Speed = directs.Contains(ni.DirectionRhumb8) ? ni.Speed * Kmk : ni.Speed; result.Add(ni); } break; default: throw new Exception("Этот тип рельефа не реализован"); } result.Height = Range.Height; result.EndChange(); actionAfter(result, param.FlugerMeteostation); return; }
/// <summary> /// получить ряд данных за указанный промежуток в заданной точке /// </summary> /// <param name="fromDate"></param> /// <param name="toDate"></param> /// <param name="point_info"></param> /// <param name="onPercentChange">Метод, вызываемый при изменении процента выполнения</param> /// <param name="checkStop"></param> /// <returns></returns> public RawRange GetRange(DateTime fromDate, DateTime toDate, NPSMeteostationInfo point_info, Action <double> onPercentChange = null, Func <bool> checkStop = null) { PointLatLng coord = point_info.Position; string fields = ""; foreach (string param in parameters.Values) { fields += param + ","; } fields = fields.Trim(','); //https://power.larc.nasa.gov/cgi-bin/v1/DataAccess.py?request=execute&identifier=SinglePoint¶meters=T2M,PS,ALLSKY_SFC_SW_DWN&startDate=20160301&endDate=20160331&userCommunity=SSE&tempAverage=DAILY&outputList=JSON,ASCII&lat=36&lon=45&user=anonymous string url = "https://power.larc.nasa.gov/cgi-bin/v1/DataAccess.py?request=execute&identifier=SinglePoint¶meters={0}&startDate={1}&endDate={2}&userCommunity=SSE&tempAverage=DAILY&outputList=ASCII&lat={3}&lon={4}&user=anonymous"; url = string.Format(url, fields, fromDate.ToString("yyyyMMdd"), toDate.ToString("yyyyMMdd"), coord.Lat.ToString("00.00").Replace(Constants.DecimalSeparator, '.'), coord.Lng.ToString("00.00").Replace(Constants.DecimalSeparator, '.')); JToken ans = SendJsonGetRequest(url, out HttpStatusCode code, false); if (checkStop != null && checkStop.Invoke()) //проверка остановки процесса { return(null); } if (ans["messages"].HasValues) //если есть ошибки, то выход с ошибкой { JToken alert = ans["messages"][0]; string msg = alert["Alert"]["Description"]["Issue"].ToString(); throw new ApplicationException(msg); } RawRange res = new RawRange(); string txt_url = ans["outputs"]["ascii"].ToString(); string data = SendStringGetRequest(txt_url, false); if (checkStop != null && checkStop.Invoke()) //проверка остановки процесса { return(null); } string dlines = data.Substring(data.IndexOf("-END HEADER-") + "-END HEADER-".Length); string[] lines = dlines.Split('\n'); for (int i = 1; i < lines.Length - 1; i++) { string line = lines[i].Replace("\r", ""); line = Regex.Replace(line, @"[ ]+", " "); string[] elems = line.Split(' '); if (elems.Length != 3 + parameters.Count) //проверка числа параметров (3 для даты, 5 - параметры атмосферы) { throw new Exception("Текстовый файл имеет неизвестный формат. Проверьте число параметров"); } try { Dictionary <MeteorologyParameters, double> values = new Dictionary <MeteorologyParameters, double>(); DateTime dt = DateTime.Parse(elems[0] + "." + elems[1] + "." + elems[2]); int ind = 3; foreach (MeteorologyParameters key in parameters.Keys) { double val = double.Parse(elems[ind].Replace('.', Constants.DecimalSeparator)); if (val == -999) { val = double.NaN; } if (key == MeteorologyParameters.Pressure) { val *= Constants.MMHGART_IN_1KPA; //переводим в мм рт. ст. } values.Add(key, val); ind++; } RawItem item = new RawItem(dt, values); res.Add(item); } catch (ArgumentException) { continue; } } res.Position = point_info.Position; return(res); }
/// <summary> /// получить ряд данных за указанный промежуток в заданной точке /// </summary> /// <param name="fromDate"></param> /// <param name="toDate"></param> /// <param name="point_info"></param> /// <param name="onPercentChange">Метод, вызываемый при изменении процента выполнения</param> /// <param name="checkStop"></param> /// <returns></returns> public RawRange GetRange(DateTime fromDate, DateTime toDate, RP5MeteostationInfo point_info, Action <double> onPercentChange = null, Func <bool> checkStop = null) { PointLatLng coord = point_info.Position; string fields = ""; foreach (string param in parameters.Values) { fields += param + ","; } fields = fields.Trim(','); //https://power.larc.nasa.gov/api/temporal/hourly/point?start=20200901&end=20210901&latitude=55&longitude=37&community=sb¶meters=WD10M&format=csv&user=anonimous&header=true&time-standard=lst string url = "https://power.larc.nasa.gov/api/temporal/hourly/point?start={1}&end={2}&latitude={3}&longitude={4}&community=sb¶meters={0}&format=csv&user=anonimous&header=true&time-standard=lst"; url = string.Format(url, fields, fromDate.ToString("yyyyMMdd"), toDate.ToString("yyyyMMdd"), coord.Lat.ToString("00.00").Replace(Constants.DecimalSeparator, '.'), coord.Lng.ToString("00.00").Replace(Constants.DecimalSeparator, '.')); string data = SendStringGetRequest(url, out HttpStatusCode code, false); if (checkStop != null && checkStop.Invoke()) //проверка остановки процесса { return(null); } if (code != HttpStatusCode.OK) //если есть ошибки, то выход с ошибкой { throw new ApplicationException("Произошла ошибка при запросе"); } RawRange res = new RawRange(); if (checkStop != null && checkStop.Invoke()) //проверка остановки процесса { return(null); } string dlines = data.Substring(data.IndexOf("-END HEADER-") + "-END HEADER-".Length); string[] lines = dlines.Split('\n'); List <string> header = new List <string>(lines[1].Split(',')); for (int i = 2; i < lines.Length - 1; i++) { string line = lines[i].Replace("\r", ""); line = Regex.Replace(line, @"[ ]+", " "); string[] elems = line.Trim().Split(','); if (header.Count != elems.Length) { continue; } try { Dictionary <MeteorologyParameters, double> values = new Dictionary <MeteorologyParameters, double>(); DateTime dt = DateTime.Parse(elems[0] + "." + elems[1] + "." + elems[2] + " " + elems[3] + ":00"); foreach (MeteorologyParameters key in parameters.Keys) { int index = header.IndexOf(parameters[key]); double val = double.Parse(elems[index].Replace('.', Constants.DecimalSeparator)); if (key == MeteorologyParameters.Pressure) { val *= Constants.MMHGART_IN_1KPA; //переводим в мм рт. ст. } values.Add(key, val); } RawItem item = new RawItem(dt, values); res.Add(item); } catch (ArgumentException) { continue; } } res.Position = point_info.Position; switch (speedHeight) { case NasaWindSpeedHeight.WS10M: res.Height = 10; break; case NasaWindSpeedHeight.WS50M: res.Height = 50; break; default: throw new Exception("Этот тип скорости не реализован"); } return(res); }
/// <summary> /// загрузка ряда из формата WindEnergy /// </summary> /// <param name="filename"></param> /// <returns></returns> private RawRange loadCSVFile(string filename) { StreamReader sr = new StreamReader(filename, Encoding.UTF8); string title = sr.ReadLine(); string coordinates = sr.ReadLine(); string name = sr.ReadLine(); sr.ReadLine();//пропуск заголовка таблицы string data = sr.ReadToEnd(); sr.Close(); RawRange res = new RawRange() { Name = name }; //чтение координат файла string regex = @"^\d+[\.\,].\d*\s+\d+[\.\,].\d*$"; bool isMatch = new Regex(regex).IsMatch(coordinates); PointLatLng coord; if (isMatch) { string[] s = coordinates.Split(' '); double lat = double.Parse(s[0].Trim().Replace('.', Constants.DecimalSeparator)); double lon = double.Parse(s[1].Trim().Replace('.', Constants.DecimalSeparator)); coord = new PointLatLng(lat, lon); } else { coord = PointLatLng.Empty; } res.Position = coord; res.BeginChange(); string[] lines = data.Split('\n'); foreach (string line in lines) { string[] elems = line.Split(';'); if (elems.Length < 6) { continue; } if (elems[3] == "") { continue; } if (elems[4] == "") { continue; } double temp = elems[1] == "" ? double.NaN : double.Parse(elems[1].Replace('.', Constants.DecimalSeparator)); DateTime dt = DateTime.Parse(elems[0]); double spd = double.Parse(elems[4].Replace('.', Constants.DecimalSeparator)); double press = double.Parse(elems[5].Replace('.', Constants.DecimalSeparator)); double wet = elems[2] == "" ? double.NaN : double.Parse(elems[2].Replace('.', Constants.DecimalSeparator)); double dirs = double.Parse(elems[3].Replace('.', Constants.DecimalSeparator)); try { res.Add(new RawItem() { Date = dt, Direction = dirs, Speed = spd, Temperature = temp, Wetness = wet, Pressure = press }); } catch (Exception) { continue; } } //поиск информации о МС RP5MeteostationInfo meteostation = null; int start = title.IndexOf("ID=") + "ID=".Length; string id_s = title.Substring(start); meteostation = Vars.RP5Meteostations.GetByID(id_s); res.Meteostation = meteostation; res.EndChange(); return(res); }
/// <summary> /// Загрузить ряд из файла csv, полученного с сайта /// </summary> /// <param name="file">файл csv</param> /// <param name="meteostation">Привязка к метеостанции. Если null, то будет найдена из БД по ID из заголовка</param> /// <returns></returns> public static RawRange LoadCSV(string file, RP5MeteostationInfo meteostation = null) { using (StreamReader sr = new StreamReader(file, Encoding.UTF8, true)) { RawRange res = new RawRange(); res.BeginChange(); //приостановка обработки событий изменения ряда //определение формата файла csv MeteoSourceType type; string title = sr.ReadLine(); if (title.Contains("WMO_ID")) { type = MeteoSourceType.Meteostation; } else if (title.Contains("METAR")) { type = MeteoSourceType.Airport; } else { throw new Exception("Файл повреждён или имеет неизвестный формат данных rp5.ru"); } //пропуск пустых строк (одна уже пропущена при чтении заголовка) for (int i = 0; i < 6; i++) { sr.ReadLine(); } switch (type) { case MeteoSourceType.Meteostation: //загрузка архива с метеостанции string data = sr.ReadToEnd(); sr.Close(); string[] lines = data.Replace("\"", "").Split('\n'); foreach (string line in lines) { string[] elems = line.Split(';'); if (elems.Length < 8) { continue; } if (elems[6] == "") { continue; } if (elems[7] == "") { continue; } double temp = elems[1] == "" ? double.NaN : double.Parse(elems[1].Replace('.', Constants.DecimalSeparator)); DateTime dt = DateTime.Parse(elems[0]); double spd = double.Parse(elems[7].Replace('.', Constants.DecimalSeparator)); double wet = elems[5] == "" ? double.NaN : double.Parse(elems[5].Replace('.', Constants.DecimalSeparator)); double press = elems[2] == "" ? double.NaN : double.Parse(elems[2].Replace('.', Constants.DecimalSeparator)); string dirs = elems[6]; WindDirections16 direct = GetWindDirectionFromString(dirs); try { res.Add(new RawItem() { Date = dt, DirectionRhumb = direct, Speed = spd, Temperature = temp, Wetness = wet, Pressure = press }); } catch (Exception) { continue; } } //поиск информации о МС if (meteostation == null) { int start = title.IndexOf("WMO_ID=") + "WMO_ID=".Length; int end = title.IndexOf(',', start); string id_s = title.Substring(start, end - start); meteostation = Vars.RP5Meteostations.GetByID(id_s); } break; case MeteoSourceType.Airport: //загрузка архива с аэропорта string data2 = sr.ReadToEnd(); sr.Close(); string[] lines2 = data2.Replace("\"", "").Split('\n'); foreach (string line in lines2) { string[] elems = line.Split(';'); if (elems.Length < 8) { continue; } if (elems[5] == "") { continue; } if (elems[6] == "") { continue; } double temp = elems[1] == "" ? double.NaN : double.Parse(elems[1].Replace('.', Constants.DecimalSeparator)); DateTime dt = DateTime.Parse(elems[0]); double spd = double.Parse(elems[6].Replace('.', Constants.DecimalSeparator)); double wet = elems[4] == "" ? double.NaN : double.Parse(elems[4].Replace('.', Constants.DecimalSeparator)); double press = elems[2] == "" ? double.NaN : double.Parse(elems[2].Replace('.', Constants.DecimalSeparator)); string dirs = elems[5]; WindDirections16 direct = RP5ru.GetWindDirectionFromString(dirs); res.Add(new RawItem() { Date = dt, DirectionRhumb = direct, Speed = spd, Temperature = temp, Wetness = wet, Pressure = press }); } //поиск информации о МС if (meteostation == null) { int start = title.IndexOf("METAR=") + "METAR=".Length; int end = title.IndexOf(',', start); string id_s = title.Substring(start, end - start); meteostation = Vars.RP5Meteostations.GetByCC_code(id_s); } break; case MeteoSourceType.UnofficialMeteostation: throw new Exception("Этот тип файла не поддерживается"); } res.Meteostation = meteostation; res.EndChange(); return(res); } }
/// <summary> /// загрузить файл данных с сайта и открыть ряд наблюдений /// </summary> /// <param name="fromDate">с какой даты</param> /// <param name="toDate">до какой даты</param> /// <param name="info">Метеостанция, с которой загружается ряд</param> /// <param name="onPercentChange"></param> /// <param name="checkStop"></param> /// <returns></returns> public RawRange GetRange(DateTime fromDate, DateTime toDate, RP5MeteostationInfo info, Action <double> onPercentChange = null, Func <bool> checkStop = null) { if (toDate < fromDate) { throw new WindEnergyException("Даты указаны неверно"); } switch (Vars.Options.RP5SourceEngine) { case RP5SourceType.LocalDBSearch: return(Vars.RP5Database.GetRange(fromDate, toDate, info, onPercentChange, checkStop)); case RP5SourceType.OnlineAPI: if (toDate - fromDate > TimeSpan.FromDays(365 * LOAD_STEP_YEARS)) // если надо скачать больше трёх лет, то скачиваем по частям { TimeSpan span = toDate - fromDate; RawRange res1 = new RawRange(); DateTime dt; int i = 0; int total = (int)(span.TotalDays / (365 * LOAD_STEP_YEARS)) + 1; for (dt = fromDate; dt <= toDate; dt += TimeSpan.FromDays(365 * LOAD_STEP_YEARS)) { if (checkStop != null) { if (checkStop.Invoke()) { break; } } if (onPercentChange != null) { double pc = ((i / (double)total) * 100d); onPercentChange.Invoke(pc); } RawRange r = GetRange(dt, dt + TimeSpan.FromDays(365 * LOAD_STEP_YEARS), info, onPercentChange, checkStop); res1.Add(r); res1.Name = r.Name; res1.Position = r.Position; res1.Meteostation = r.Meteostation; res1.Height = 10; //высота всегда 10м i++; } //DateTime fr = dt - TimeSpan.FromDays(365 * LOAD_STEP_YEARS); //RawRange r1 = GetRange(fr, toDate, info); return(res1); } #region отправка статистики загрузки string dataS, linkS; switch (info.MeteoSourceType) { case MeteoSourceType.Airport: dataS = "cc_id={0}&cc_str={1}&stat_p=1&s_date1={2}&s_ed3={4}&s_ed4={4}&s_ed5={5}&s_date2={3}&s_ed9=0&s_ed10=-1&s_pe=1&lng_id=2&s_dtimehi=-Период---"; linkS = "https://rp5.ru/responses/reStatistMetar.php"; dataS = string.Format(dataS, info.ID, //cc_id info.CC_Code, //cc_str fromDate.Date.ToString("dd.MM.yyyy"), //from toDate.Date.ToString("dd.MM.yyyy"), //to DateTime.Now.Month, //f_ed3 - только месяц DateTime.Now.Day //f_ed5 - только день ); break; case MeteoSourceType.Meteostation: dataS = "wmo_id={0}&stat_p=1&s_date1={1}&s_ed3={3}&s_ed4={3}&s_ed5={4}&s_date2={2}&s_ed9=0&s_ed10=-1&s_pe=1&lng_id=2&s_dtimehi=-срок---"; linkS = "https://rp5.ru/responses/reStatistSynop.php"; dataS = string.Format(dataS, info.ID, //wmo_id fromDate.Date.ToString("dd.MM.yyyy"), //from toDate.Date.ToString("dd.MM.yyyy"), //to DateTime.Now.Month, //f_ed3 - только месяц DateTime.Now.Day //f_ed5 - только день ); break; default: throw new Exception("Этот тип метеостанций не реализован"); } string strS = this.SendStringPostRequest(linkS, dataS, referer: "https://rp5.ru/", cookies: this.CookieData, customHeaders: this.Headers); #endregion #region получение ссылки на файл string data, link; //получение ссылки на файл switch (info.MeteoSourceType) { case MeteoSourceType.Airport: data = "metar={0}&a_date1={1}&a_date2={2}&f_ed3={3}&f_ed4={4}&f_ed5={5}&f_pe={6}&f_pe1={7}&lng_id=2"; link = "https://rp5.ru/responses/reFileMetar.php"; break; case MeteoSourceType.Meteostation: data = "wmo_id={0}&a_date1={1}&a_date2={2}&f_ed3={3}&f_ed4={4}&f_ed5={5}&f_pe={6}&f_pe1={7}&lng_id=2"; link = "https://rp5.ru/responses/reFileSynop.php"; break; default: throw new Exception("Этот тип метеостанций не реализован"); } data = string.Format(data, info.ID, //id fromDate.Date.ToString("dd.MM.yyyy"), //from toDate.Date.ToString("dd.MM.yyyy"), //to DateTime.Now.Month, //f_ed3 - только месяц DateTime.Now.Month, //f_ed4 - только месяц DateTime.Now.Day, //f_ed5 - только день 1, //f_pe 2 //f_pe1- кодировка (1 - ansi, 2 - utf8, 3 - Unicode) ); string str = this.SendStringPostRequest(link, data, referer: "https://rp5.ru/", cookies: this.CookieData, customHeaders: this.Headers); //ОШИБКИ rp5.ru //запросы к reFileSynop.php //FS004 несуществующий wmo_id //FS002 ошибки в исходных данных (параметрах запроса) //FS000 Ошибка авторизации //FS001- //запросы к reStatistSynop.php //S000 Ошибка авторизации //FM000 Время жизни статистики истекло для этой сессии if (str.Contains("FS004")) { throw new WindEnergyException("Для этого id нет архива погоды", ErrorReason.FS004); } if (str.Contains("FS002")) { throw new WindEnergyException("Ошибка в исходных данных", ErrorReason.FS002); } if (str.Contains("FS000")) { throw new WindEnergyException("Ошибка авторизации", ErrorReason.FS000); } if (str.Contains("FS001-")) { throw new WindEnergyException("Неправильный метод запроса. Ожидается POST", ErrorReason.FS001); } if (str.Contains("FM000")) { throw new WindEnergyException("Время жизни статистики истекло для этой сессии", ErrorReason.FM000); } if (str.Contains("FM004")) { throw new WindEnergyException("Внутренняя ошибка. Архив недоступен или не существует", ErrorReason.FM004); } int start = str.IndexOf("href=") + 5; str = str.Substring(start); int end = str.IndexOf(">"); string lnk = str.Substring(0, end); lnk = lnk.Split(' ')[0] ?? ""; bool checkLink = Uri.TryCreate(lnk, UriKind.Absolute, out Uri uriResult) && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps); if (!checkLink) { throw new WindEnergyException("В парсере ответа rp5 произошла ошибка. Скорее всего, парсер устарел, обратитесь к разработчику"); } #endregion #region загрузка файла с сервера string tmp_dl_file = Vars.LocalFileSystem.GetTempFileName(); WebClient webcl = new WebClient(); webcl.DownloadFile(lnk, tmp_dl_file); webcl.Dispose(); //распаковка string tmp_unpack_file = tmp_dl_file + ".csv"; LocalFileSystem.UnGZip(tmp_dl_file, tmp_unpack_file); //открытие файла RawRange res = LoadCSV(tmp_unpack_file, info); res = new RawRange(res.OrderBy(x => x.Date).ToList()); res.Name = info.Name; res.Position = info.Position; res.Meteostation = info; res.Height = 10; //высота всегда 10м new Task(() => Vars.RP5Meteostations.TryAddMeteostation(info)).Start(); //если такой метеостанции нет в БД, то добавляем return(res); #endregion default: throw new Exception("Этот тип БД не реализован"); } }