private void Window_PreviewMouseDown(object sender, MouseButtonEventArgs e) { Storm Sto = CurrentProject.SelectedBasin.GetCurrentStorm(); if (Sto != null) { if (Sto.LastNode != null) { Node LastNode = Sto.LastNode; RelativePositionConverter RPC = new RelativePositionConverter(); RelativePosition RP = (RelativePosition)RPC.Convert(e.GetPosition(HurricaneBasin), typeof(RelativePosition), null, null); LastNode.Position = RP; Sto.AddNode(LastNode); LastNode = null; } } else { // left mouse button clicked (no zoom) if (e.LeftButton == MouseButtonState.Pressed) { Project CurProj = CurrentProject; // fix retardation if (CurProj != null && CurProj.SelectedBasin != null && CurProj.SelectedBasin.CurrentLayer != null) { // if we have no storms, ask the user to create a storm instead of add a track point. if (Sto == null) { AddNewStormHost Addstwindow = new AddNewStormHost(CurProj.SelectedBasin.SeasonStartTime); Addstwindow.Owner = this; Addstwindow.Show(); return; } else { // build 524 #if PRISCILLA StormTypeManager ST2M = ST2Manager; #else StormTypeManager ST2Manager = GlobalState.GetST2Manager(); #endif Storm SelectedStorm = CurProj.SelectedBasin.GetCurrentStorm(); int NodeCount = SelectedStorm.NodeList.Count - 1; // build 547: implement season start time on window feature AddTrackPointHost ATPHost = new AddTrackPointHost(ST2M.GetListOfStormTypeNames(), e.GetPosition(HurricaneBasin), SelectedStorm.GetNodeDate(NodeCount)); ATPHost.Owner = this; ATPHost.Show(); } } } else if (e.RightButton == MouseButtonState.Pressed) { // temporary code // this should be a matrix transformation but /shrug // not best practice LastRightMouseClickPos = e.GetPosition(HurricaneBasin); } } }
/// <summary> /// Needs to be majorly updated and refactored for v2 /// </summary> /// <param name="basin"></param> /// <returns></returns> public bool ExportCore(Project Project, string FileName) { Directory.CreateDirectory(FileName); Basin SelBasin = Project.SelectedBasin; // create a file for each storm foreach (Storm Storm in SelBasin.GetFlatListOfStorms()) { if (Storm.Name.Length > 12) { // Woah, calm it (Priscilla 442) Error.Throw("Error", "This format, the ATCF BestTrack format, has several limitations (and is obsolete to begin with). Exporting to this format is not recommended. \n\nLimitations:\n\n- It does not support storms with names with a length above twelve characters.\n- It does not support abbreviated character names of lengths more than three characters.\n- It uses exceedingly bizarre spelling.\nIt is from the 1980s.\n\n- There is no documentation on the Internet, despite extensive efforts to acquire some.", ErrorSeverity.Error, 131); return(false); } string StormFileName = Path.Combine(FileName, $@"{Storm.Name}.dat"); // Create a new file for each storm. using (StreamWriter SW = new StreamWriter(new FileStream(StormFileName, FileMode.Create))) { // For each node. foreach (Node Node in Storm.NodeList) { if (!Node.IsRealType()) { Error.Throw("Error", "Custom storm types are not supported when exporting to ATCF/HURDAT2 format.", ErrorSeverity.Error, 248); return(false); } if (SelBasin.Abbreviation != null) { SW.Write($"{SelBasin.Abbreviation}, "); } else { SW.Write($"{SelBasin.Name}, "); } // Pad with a zero if <10 and write storm id. SW.Write($"{Utilities.PadZero(Storm.Id + 1)}, "); // Get the node date DateTime NodeDate = Storm.GetNodeDate(Node.Id); SW.Write($"{NodeDate.ToString("yyyyMMdd")}{Utilities.PadZero(NodeDate.Hour)}"); // Some weird padding shit (It's actually time since system formation. Who knew???) SW.Write(", , "); // Best marker, more useless padding SW.Write("BEST, "); // God knows what this does SW.Write("0, "); // Node position. Category Cat = Storm.GetNodeCategory(Node, GlobalState.CategoryManager.CurrentCategorySystem); Coordinate X = Project.SelectedBasin.FromNodePositionToCoordinate(Node.Position, VolatileApplicationSettings.WindowSize); SW.Write($"{X.Coordinates.X}{X.Directions[0]}, {X.Coordinates.Y}{X.Directions[1]}, "); // Intensity. for (int i = 0; i < 4 - Node.Intensity.ToString().Length; i++) { SW.Write(" "); } // Convert to KT (DANO: MOVE TO DEDICATED HurricaneConversions CLASS) double Intensity = Utilities.RoundNearest(Node.Intensity / 1.151, 5); SW.Write($"{Intensity}, "); // Pressure. We don't do this until dano and even then it will be optional. Just put 1000mbars SW.Write($"{Node.Pressure}, "); // Write the category and a WHOLE bunch of information that we don't need or use yet - environmental pressure etc - I don't know what most of these are tbh CategorySystem CurrentCategorySystem = GlobalState.CategoryManager.CurrentCategorySystem; Category Ct = Storm.GetNodeCategory(Node, CurrentCategorySystem); // v610: fix crash when exporting projects with invalid categories (i.e. storm too intense) iris: add palceholder if (Ct == null) { Ct = CurrentCategorySystem.GetHighestCategory(); } string CatString = null; if (Ct.Abbreviation == null) { int SplitLength = CatString.Split(' ').Length; CatString = Cat.GetAbbreviatedCategoryName(CatString, SplitLength, 0, 1, true); } else { CatString = Ct.Abbreviation; } Debug.Assert(CatString != null); if (CatString.Length > 3) { MessageBox.Show("Due to the limitations of the ATCF format, category names cannot be longer than 3 characters abbreviated."); return(false); } // Placeholder information for (int i = 0; i < 3 - CatString.Length; i++) { SW.Write(" "); } SW.Write($"{CatString}, "); // todo: abbreviate (dano) // Aforementioned information SW.Write($"x, 0, , 0, 0, 0, 0, 1014, 90, 60, 0, 0, L, 0, , 0, 0, "); // Shit Format for (int i = 0; i < (12 - Storm.Name.Length); i++) { SW.Write(" "); } SW.Write(Storm.Name); // More pointless and irrelevant data. SW.Write(", M, 0, , 0, 0, 0, 0, "); // Why does this exist SW.Write("genesis-num, "); SW.Write(Utilities.PadZero(Storm.Id + 1, 2)); SW.Write(", \n"); // Write newline // on success GlobalState.SetCurrentOpenFile(FileName); } } } return(true); }