// used by historylist directly for a single update during play, in foreground.. Also used by above.. so can be either in fore/back public bool AddSAASignalsFoundToBestSystem(JournalSAASignalsFound jsaa, int startindex, List <HistoryEntry> hl) { if (jsaa.Signals == null) // be paranoid, don't add if null signals { return(false); } for (int j = startindex; j >= 0; j--) { HistoryEntry he = hl[j]; if (he.IsLocOrJump) { JournalLocOrJump jl = (JournalLocOrJump)he.journalEntry; string designation = GetBodyDesignationSAASignalsFound(jsaa, he.System.Name); if (IsStarNameRelated(he.System.Name, designation)) // if its part of the name, use it { jsaa.BodyDesignation = designation; return(ProcessSAASignalsFound(jsaa, he.System, true)); } else if (jl != null && IsStarNameRelated(jl.StarSystem, designation)) { // Ignore scans where the system name has changed return(false); } } } jsaa.BodyDesignation = GetBodyDesignationSAASignalsFound(jsaa, hl[startindex].System.Name); return(ProcessSAASignalsFound(jsaa, hl[startindex].System, true)); // no relationship, add.. }
// this tries to reprocess any JEs associated with a system node which did not have scan data at the time. // Seen to work with log from Issue #2983 private void ProcessedSaved(SystemNode sn) { if (sn.ToProcess != null) { List <Tuple <JournalEntry, ISystem> > todelete = new List <Tuple <JournalEntry, ISystem> >(); foreach (var e in sn.ToProcess) { JournalSAAScanComplete jsaasc = e.Item1 as JournalSAAScanComplete; if (jsaasc != null) { if (ProcessSAAScan(jsaasc, e.Item2, false)) { todelete.Add(e); } } JournalSAASignalsFound jsaasf = e.Item1 as JournalSAASignalsFound; if (jsaasf != null) { if (ProcessSAASignalsFound(jsaasf, e.Item2, false)) { todelete.Add(e); } } } foreach (var je in todelete) { sn.ToProcess.Remove(je); } } }
private string GetBodyDesignationSAASignalsFound(JournalSAASignalsFound je, string system) { if (je.BodyName == null || system == null) { return(null); } string bodyname = je.BodyName; int bodyid = (int)je.BodyID; if (bodyIdDesignationMap.ContainsKey(system) && bodyIdDesignationMap[system].ContainsKey(bodyid) && bodyIdDesignationMap[system][bodyid].NameEquals(bodyname)) { return(bodyIdDesignationMap[system][bodyid].Designation); } if (planetDesignationMap.ContainsKey(system) && planetDesignationMap[system].ContainsKey(bodyname)) { return(planetDesignationMap[system][bodyname]); } if (bodyname.Equals(system, StringComparison.InvariantCultureIgnoreCase) || bodyname.StartsWith(system + " ", StringComparison.InvariantCultureIgnoreCase)) { return(bodyname); } return(bodyname); }
// Async task to find results given cond in helist, using only vars specified. private System.Threading.Tasks.Task <List <Tuple <ISystem, object[]> > > Find(List <HistoryEntry> helist, BaseUtils.ConditionLists cond, HashSet <string> varsusedincondition, ISystem cursystem) { return(System.Threading.Tasks.Task.Run(() => { List <Tuple <ISystem, object[]> > rows = new List <Tuple <ISystem, object[]> >(); foreach (var he in helist) { BaseUtils.Variables scandata = new BaseUtils.Variables(); scandata.AddPropertiesFieldsOfClass(he.journalEntry, "", new Type[] { typeof(System.Drawing.Icon), typeof(System.Drawing.Image), typeof(System.Drawing.Bitmap), typeof(QuickJSON.JObject) }, 5, varsusedincondition); bool?res = cond.CheckAll(scandata, out string errlist, out BaseUtils.ConditionLists.ErrorClass errclass); // need function handler.. if (res.HasValue && res.Value == true) { ISystem sys = he.System; string sep = System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator + " "; JournalScan js = he.journalEntry as JournalScan; JournalFSSBodySignals jb = he.journalEntry as JournalFSSBodySignals; JournalSAASignalsFound jbs = he.journalEntry as JournalSAASignalsFound; string name, info; if (js != null) { name = js.BodyName; info = js.DisplayString(0); } else if (jb != null) { name = jb.BodyName; jb.FillInformation(he.System, "", out info, out string d); } else { name = jbs.BodyName; jbs.FillInformation(he.System, "", out info, out string d); } object[] rowobj = { EDDConfig.Instance.ConvertTimeToSelectedFromUTC(he.EventTimeUTC).ToString(), name, info, (cursystem != null ? cursystem.Distance(sys).ToString("0.#") : ""), sys.X.ToString("0.#") + sep + sys.Y.ToString("0.#") + sep + sys.Z.ToString("0.#") }; rows.Add(new Tuple <ISystem, object[]>(sys, rowobj)); } } return rows; })); }
public JObject CreateEDDNMessage(JournalSAASignalsFound journal, ISystem system) { if (system.SystemAddress == null) { return(null); } // Reject scan if system doesn't match scan system if (journal.SystemAddress != system.SystemAddress) { return(null); } JObject msg = new JObject(); msg["header"] = Header(); msg["$schemaRef"] = GetEDDNJournalSchemaRef(); JObject message = journal.GetJsonCloned(); if (message == null) { return(null); } message["StarSystem"] = system.Name; message["StarPos"] = new JArray(new float[] { (float)system.X, (float)system.Y, (float)system.Z }); message["SystemAddress"] = system.SystemAddress; if (message["Signals"] != null && message["Signals"] is JArray) { foreach (JObject sig in message["Signals"]) { sig.Remove("Type_Localised"); } } message = RemoveCommonKeys(message); message = FilterJournalEvent(message, AllowedFieldsSAASignalsFound); message["odyssey"] = journal.IsOdyssey; // new may 21 message["horizons"] = journal.IsHorizons; msg["message"] = message; return(msg); }
// used by historylist directly for a single update during play, in foreground.. Also used by above.. so can be either in fore/back public bool AddSAASignalsFoundToBestSystem(JournalSAASignalsFound jsaa, int startindex, List <HistoryEntry> hl) { if (jsaa.Signals == null || jsaa.BodyName == null) // be paranoid, don't add if null signals { return(false); } var best = FindBestSystem(startindex, hl, jsaa.BodyName, jsaa.BodyID, false); if (best == null) { return(false); } jsaa.BodyDesignation = best.Item1; return(ProcessSAASignalsFound(jsaa, best.Item2)); }
private void ProcessedSaved() { List <Tuple <JournalEntry, ISystem> > todelete = new List <Tuple <JournalEntry, ISystem> >(); foreach (var e in ToProcess) { JournalSAAScanComplete jsaasc = e.Item1 as JournalSAAScanComplete; if (jsaasc != null) { if (ProcessSAAScan(jsaasc, e.Item2, false)) { todelete.Add(e); } } JournalSAASignalsFound jsaasf = e.Item1 as JournalSAASignalsFound; if (jsaasf != null) { if (ProcessSAASignalsFound(jsaasf, e.Item2, false)) { todelete.Add(e); } } JournalFSSSignalDiscovered jssdis = e.Item1 as JournalFSSSignalDiscovered; if (jssdis != null) { if (AddFSSSignalsDiscoveredToSystem(jssdis, null, false)) { todelete.Add(e); } } } foreach (var je in todelete) { ToProcess.Remove(je); } }
Dictionary <Bitmap, float> imageintensities = new Dictionary <Bitmap, float>(); // cached // return right bottom of area used from curpos Point DrawNode(List <ExtPictureBox.ImageElement> pc, StarScan.ScanNode sn, MaterialCommoditiesList curmats, // curmats may be null HistoryList hl, Image notscanned, // image if sn is not known Point position, // position is normally left/middle, unless xiscentre is set. bool xiscentre, out Rectangle imagepos, Size size, // nominal size DrawLevel drawtype, // drawing.. Color?backwash = null, // optional back wash on image string appendlabeltext = "" // any label text to append ) { string tip; Point endpoint = position; imagepos = Rectangle.Empty; JournalScan sc = sn.ScanData; if (sc != null && (!sc.IsEDSMBody || CheckEDSM)) // has a scan and its our scan, or we are showing EDSM { if (sn.NodeType != StarScan.ScanNodeType.ring) // not rings { tip = sc.DisplayString(historicmatlist: curmats, currentmatlist: hl.GetLast?.MaterialCommodity); if (sn.Signals != null) { tip += "\n" + "Signals".T(EDTx.ScanDisplayUserControl_Signals) + ":\n" + JournalSAASignalsFound.SignalList(sn.Signals, 4, "\n"); } Bitmap nodeimage = (Bitmap)(sc.IsStar ? sc.GetStarTypeImage() : sc.GetPlanetClassImage()); string overlaytext = ""; var nodelabels = new string[2] { "", "" }; nodelabels[0] = sn.CustomNameOrOwnname; if (sc.IsEDSMBody) { nodelabels[0] = "_" + nodelabels[0]; } if (sc.IsStar) { if (ShowStarClasses) { overlaytext = sc.StarClassificationAbv; } if (sc.nStellarMass.HasValue) { nodelabels[1] = nodelabels[1].AppendPrePad($"{sc.nStellarMass.Value:N2} SM", Environment.NewLine); } if (drawtype == DrawLevel.TopLevelStar) { if (sc.nAge.HasValue) { nodelabels[1] = nodelabels[1].AppendPrePad($"{sc.nAge.Value:N0} MY", Environment.NewLine); } if (ShowHabZone) { var habZone = sc.GetHabZoneStringLs(); if (habZone.HasChars()) { nodelabels[1] = nodelabels[1].AppendPrePad($"{habZone}", Environment.NewLine); } } } } else { if (ShowPlanetClasses) { overlaytext = Bodies.PlanetAbv(sc.PlanetTypeID); } if ((sn.ScanData.IsLandable || ShowAllG) && sn.ScanData.nSurfaceGravity != null) { nodelabels[1] = nodelabels[1].AppendPrePad($"{(sn.ScanData.nSurfaceGravity / JournalScan.oneGee_m_s2):N2}g", Environment.NewLine); } } if (ShowDist) { if (drawtype != DrawLevel.MoonLevel) // other than moons { if (sn.ScanData.IsOrbitingBaryCentre) // if in orbit of barycentre { string s = $"{(sn.ScanData.DistanceFromArrivalLS):N1}ls"; if (sn.ScanData.nSemiMajorAxis.HasValue) { s += "/" + sn.ScanData.SemiMajorAxisLSKM; } nodelabels[1] = nodelabels[1].AppendPrePad(s, Environment.NewLine); } else { //System.Diagnostics.Debug.WriteLine(sn.ScanData.BodyName + " SMA " + sn.ScanData.nSemiMajorAxis + " " + sn.ScanData.DistanceFromArrivalm); string s = sn.ScanData.nSemiMajorAxis.HasValue && Math.Abs(sn.ScanData.nSemiMajorAxis.Value - sn.ScanData.DistanceFromArrivalm) > JournalScan.oneAU_m ? (" / " + sn.ScanData.SemiMajorAxisLSKM) : ""; nodelabels[1] = nodelabels[1].AppendPrePad($"{sn.ScanData.DistanceFromArrivalLS:N1}ls" + s, Environment.NewLine); } } else { if (!sn.ScanData.IsOrbitingBaryCentre && sn.ScanData.nSemiMajorAxis.HasValue) // if not in orbit of barycentre { nodelabels[1] = nodelabels[1].AppendPrePad($"{(sn.ScanData.nSemiMajorAxis / JournalScan.oneLS_m):N1}ls", Environment.NewLine); } } } nodelabels[1] = nodelabels[1].AppendPrePad(appendlabeltext, Environment.NewLine); // nodelabels[1] = nodelabels[1].AppendPrePad("" + sn.ScanData?.BodyID, Environment.NewLine); bool valuable = sc.EstimatedValue >= ValueLimit; bool isdiscovered = sc.IsPreviouslyDiscovered && sc.IsPlanet; int iconoverlays = ShowOverlays ? ((sc.Terraformable ? 1 : 0) + (sc.HasMeaningfulVolcanism ? 1 : 0) + (valuable ? 1 : 0) + (sc.Mapped ? 1 : 0) + (isdiscovered ? 1 : 0) + (sc.IsPreviouslyMapped ? 1 : 0) + (sn.Signals != null ? 1 : 0)) : 0; // if (sc.BodyName.Contains("4 b")) iconoverlays = 0; bool materialsicon = sc.HasMaterials && !ShowMaterials; bool imageoverlays = sc.IsLandable || (sc.HasRings && drawtype != DrawLevel.TopLevelStar) || materialsicon; int bitmapheight = size.Height * nodeheightratio / noderatiodivider; int overlaywidth = bitmapheight / 6; int imagewidtharea = (imageoverlays ? 2 : 1) * size.Width; // area used by image+overlay if any int iconwidtharea = (iconoverlays > 0 ? overlaywidth : 0); // area used by icon width area on left int bitmapwidth = iconwidtharea + imagewidtharea; // total width int imageleft = iconwidtharea + imagewidtharea / 2 - size.Width / 2; // calculate where the left of the image is int imagetop = bitmapheight / 2 - size.Height / 2; // and the top Bitmap bmp = new Bitmap(bitmapwidth, bitmapheight); using (Graphics g = Graphics.FromImage(bmp)) { // backwash = Color.FromArgb(128, 40, 40, 40); // debug if (backwash.HasValue) { using (Brush b = new SolidBrush(backwash.Value)) { g.FillRectangle(b, new Rectangle(iconwidtharea, 0, imagewidtharea, bitmapheight)); } } g.DrawImage(nodeimage, imageleft, imagetop, size.Width, size.Height); if (sc.IsLandable) { int offset = size.Height * 4 / 16; int scale = 5; g.DrawImage(Icons.Controls.Scan_Bodies_Landable, new Rectangle(imageleft + size.Width / 2 - offset * scale / 2, imagetop + size.Height / 2 - offset * scale / 2, offset * scale, offset * scale)); } if (sc.HasRings && drawtype != DrawLevel.TopLevelStar) { g.DrawImage(sc.Rings.Count() > 1 ? Icons.Controls.Scan_Bodies_RingGap : Icons.Controls.Scan_Bodies_RingOnly, new Rectangle(imageleft - size.Width / 2, imagetop, size.Width * 2, size.Height)); } if (iconoverlays > 0) { int ovsize = bmp.Height / 6; int pos = 4; if (sc.Terraformable) { g.DrawImage(Icons.Controls.Scan_Bodies_Terraformable, new Rectangle(0, pos, ovsize, ovsize)); pos += ovsize + 1; } if (sc.HasMeaningfulVolcanism) //this renders below the terraformable icon if present { g.DrawImage(Icons.Controls.Scan_Bodies_Volcanism, new Rectangle(0, pos, ovsize, ovsize)); pos += ovsize + 1; } if (valuable) { g.DrawImage(Icons.Controls.Scan_Bodies_HighValue, new Rectangle(0, pos, ovsize, ovsize)); pos += ovsize + 1; } if (sc.Mapped) { g.DrawImage(Icons.Controls.Scan_Bodies_Mapped, new Rectangle(0, pos, ovsize, ovsize)); pos += ovsize + 1; } if (sc.IsPreviouslyMapped) { g.DrawImage(Icons.Controls.Scan_Bodies_MappedByOthers, new Rectangle(0, pos, ovsize, ovsize)); pos += ovsize + 1; } if (isdiscovered) { g.DrawImage(Icons.Controls.Scan_Bodies_DiscoveredByOthers, new Rectangle(0, pos, ovsize, ovsize)); pos += ovsize + 1; } if (sn.Signals != null) { g.DrawImage(Icons.Controls.Scan_Bodies_Signals, new Rectangle(0, pos, ovsize, ovsize)); } } if (materialsicon) { Image mm = Icons.Controls.Scan_Bodies_MaterialMore; g.DrawImage(mm, new Rectangle(bmp.Width - mm.Width, bmp.Height - mm.Height, mm.Width, mm.Height)); } if (overlaytext.HasChars()) { float ii; if (imageintensities.ContainsKey(nodeimage)) // find cache { ii = imageintensities[nodeimage]; //System.Diagnostics.Debug.WriteLine("Cached Image intensity of " + sn.fullname + " " + ii); } else { var imageintensity = nodeimage.Function(BitMapHelpers.BitmapFunction.Brightness, nodeimage.Width * 3 / 8, nodeimage.Height * 3 / 8, nodeimage.Width * 2 / 8, nodeimage.Height * 2 / 8); ii = imageintensity.Item2; imageintensities[nodeimage] = ii; //System.Diagnostics.Debug.WriteLine("Calculated Image intensity of " + sn.fullname + " " + ii); } Color text = ii > 0.3f ? Color.Black : Color.FromArgb(255, 200, 200, 200); using (Font f = new Font(EDDTheme.Instance.FontName, size.Width / 5.0f)) { using (Brush b = new SolidBrush(text)) { g.DrawString(overlaytext, f, b, new Rectangle(iconwidtharea, 0, bitmapwidth - iconwidtharea, bitmapheight), new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }); } } } } // need left middle, if xiscentre, translate to it Point postoplot = xiscentre ? new Point(position.X - bmp.Width / 2, position.Y) : position; //System.Diagnostics.Debug.WriteLine("Body " + sc.BodyName + " plot at " + postoplot + " " + bmp.Size + " " + (postoplot.X+imageleft) + "," + (postoplot.Y-bmp.Height/2+imagetop)); endpoint = CreateImageAndLabel(pc, bmp, postoplot, bmp.Size, out imagepos, nodelabels, tip); //System.Diagnostics.Debug.WriteLine("Draw {0} at {1} {2} out {3}", nodelabels[0], postoplot, bmp.Size, imagepos); if (sc.HasMaterials && ShowMaterials) { Point matpos = new Point(endpoint.X + 4, position.Y); Point endmat = CreateMaterialNodes(pc, sc, curmats, hl, matpos, materialsize); endpoint = new Point(Math.Max(endpoint.X, endmat.X), Math.Max(endpoint.Y, endmat.Y)); // record new right point.. } } } else if (sn.NodeType == StarScan.ScanNodeType.belt) { if (sn.BeltData != null) { tip = sn.BeltData.RingInformationMoons(true, ""); } else { tip = sn.OwnName + Environment.NewLine + Environment.NewLine + "No scan data available".T(EDTx.ScanDisplayUserControl_NSD); } if (sn.Children != null && sn.Children.Count != 0) { foreach (StarScan.ScanNode snc in sn.Children.Values) { if (snc.ScanData != null) { string sd = snc.ScanData.DisplayString() + "\n"; tip += "\n" + sd; } } } Size bmpsize = new Size(size.Width, planetsize.Height * nodeheightratio / noderatiodivider); endpoint = CreateImageAndLabel(pc, Icons.Controls.Scan_Bodies_Belt, position, bmpsize, out imagepos, new string[] { sn.OwnName.AppendPrePad(appendlabeltext, Environment.NewLine) }, tip, false); } else { if (sn.NodeType == StarScan.ScanNodeType.barycentre) { tip = string.Format("Barycentre of {0}".T(EDTx.ScanDisplayUserControl_BC), sn.OwnName); } else { tip = sn.OwnName + Environment.NewLine + Environment.NewLine + "No scan data available".T(EDTx.ScanDisplayUserControl_NSD); } string nodelabel = sn.CustomName ?? sn.OwnName; nodelabel = nodelabel.AppendPrePad(appendlabeltext, Environment.NewLine); endpoint = CreateImageAndLabel(pc, notscanned, position, size, out imagepos, new string[] { nodelabel }, tip, false); } // System.Diagnostics.Debug.WriteLine("Node " + sn.ownname + " " + position + " " + size + " -> "+ endpoint); return(endpoint); }
private bool ProcessSAASignalsFound(JournalSAASignalsFound jsaa, ISystem sys, bool reprocessPrimary = false) // background or foreground.. FALSE if you can't process it { SystemNode sn = GetOrCreateSystemNode(sys); ScanNode relatednode = null; if (sn.NodesByID.ContainsKey((int)jsaa.BodyID)) // find by ID { relatednode = sn.NodesByID[(int)jsaa.BodyID]; if (relatednode.ScanData != null && relatednode.ScanData.BodyDesignation != null) { jsaa.BodyDesignation = relatednode.ScanData.BodyDesignation; } } else if (jsaa.BodyDesignation != null && jsaa.BodyDesignation != jsaa.BodyName) { foreach (var body in sn.Bodies) { if (body.fullname == jsaa.BodyDesignation) { relatednode = body; break; } } } if (relatednode != null && relatednode.type == ScanNodeType.ring && relatednode.ScanData != null && relatednode.ScanData.Parents != null && sn.NodesByID.ContainsKey(relatednode.ScanData.Parents[0].BodyID)) { relatednode = sn.NodesByID[relatednode.ScanData.Parents[0].BodyID]; } if (relatednode == null || relatednode.type == ScanNodeType.ring) { bool ringname = jsaa.BodyName.EndsWith("A Ring") || jsaa.BodyName.EndsWith("B Ring") || jsaa.BodyName.EndsWith("C Ring") || jsaa.BodyName.EndsWith("D Ring"); string ringcutname = ringname ? jsaa.BodyName.Left(jsaa.BodyName.Length - 6).TrimEnd() : null; foreach (var body in sn.Bodies) { if ((body.fullname == jsaa.BodyName || body.customname == jsaa.BodyName) && (body.fullname != sys.Name || body.level != 0)) { relatednode = body; break; } else if (ringcutname != null && body.fullname.Equals(ringcutname)) { relatednode = body; break; } } } if (relatednode != null) { //System.Diagnostics.Debug.WriteLine("Setting SAA Signals Found for " + jsaa.BodyName + " @ " + sys.Name + " body " + jsaa.BodyDesignation); if (relatednode.Signals == null) { relatednode.Signals = new List <JournalSAASignalsFound.SAASignal>(); } relatednode.Signals.AddRange(jsaa.Signals); // add signals to list of signals of this entity return(true); // all ok } return(false); }
private bool ProcessSAASignalsFound(JournalSAASignalsFound jsaa, ISystem sys, bool saveprocessinglater = true) // background or foreground.. FALSE if you can't process it { SystemNode sn = GetOrCreateSystemNode(sys); ScanNode relatednode = null; if (sn.NodesByID.ContainsKey((int)jsaa.BodyID)) // find by ID { relatednode = sn.NodesByID[(int)jsaa.BodyID]; if (relatednode.ScanData != null && relatednode.ScanData.BodyDesignation != null) { jsaa.BodyDesignation = relatednode.ScanData.BodyDesignation; } } else if (jsaa.BodyDesignation != null && jsaa.BodyDesignation != jsaa.BodyName) { foreach (var body in sn.Bodies) { if (body.FullName == jsaa.BodyDesignation) { relatednode = body; break; } } } if (relatednode != null && relatednode.NodeType == ScanNodeType.ring && relatednode.ScanData != null && relatednode.ScanData.Parents != null && sn.NodesByID.ContainsKey(relatednode.ScanData.Parents[0].BodyID)) { relatednode = sn.NodesByID[relatednode.ScanData.Parents[0].BodyID]; } if (relatednode == null || relatednode.NodeType == ScanNodeType.ring) { bool ringname = jsaa.BodyName.EndsWith("A Ring") || jsaa.BodyName.EndsWith("B Ring") || jsaa.BodyName.EndsWith("C Ring") || jsaa.BodyName.EndsWith("D Ring"); string ringcutname = ringname ? jsaa.BodyName.Left(jsaa.BodyName.Length - 6).TrimEnd() : null; foreach (var body in sn.Bodies) { if ((body.FullName == jsaa.BodyName || body.CustomName == jsaa.BodyName) && (body.FullName != sys.Name || body.Level != 0)) { relatednode = body; break; } else if (ringcutname != null && body.FullName.Equals(ringcutname)) { relatednode = body; break; } } } if (relatednode != null) { // System.Diagnostics.Debug.WriteLine("Setting SAA Signals Found for " + jsaa.BodyName + " @ " + sys.Name + " body " + jsaa.BodyDesignation); if (relatednode.Signals == null) { relatednode.Signals = new List <JournalSAASignalsFound.SAASignal>(); } foreach (var x in jsaa.Signals) { if (relatednode.Signals.Find(y => y.Type == x.Type && y.Count == x.Count) == null) { relatednode.Signals.Add(x); } } } else { if (saveprocessinglater) { SaveForProcessing(jsaa, sys); } // System.Diagnostics.Debug.WriteLine("No body to attach data found for " + jsaa.BodyName + " @ " + sys.Name + " body " + jsaa.BodyDesignation); } return(false); }
// Width: Nodes are allowed 2 widths // Height: Nodes are allowed 1.5 Heights. 0 = top, 1/2/3/4 = image, 5 = bottom. // offset: pass in horizonal offset, return back middle of image // aligndown : if true, compensate for drawing normal size images and ones 1.5 by shifting down the image and the label by the right amounts // labelvoff : any additional compensation for label pos // return right bottom of area used from curpos // curmats may be null Point DrawNode(List <ExtPictureBox.ImageElement> pc, StarScan.ScanNode sn, MaterialCommoditiesList curmats, HistoryList hl, Image notscanned, Point curpos, Size size, ref int offset, bool aligndown = false, int labelvoff = 0, bool toplevel = false) { string tip; Point endpoint = curpos; int quarterheight = size.Height / 4; int alignv = aligndown ? quarterheight : 0; JournalScan sc = sn.ScanData; //System.Diagnostics.Debug.WriteLine("Node " + sn.ownname + " " + curpos + " " + size + " hoff " + offset + " EDSM " + ((sc!= null) ? sc.IsEDSMBody.ToString() : "")); if (sc != null && (!sc.IsEDSMBody || CheckEDSM)) // if got one, and its our scan, or we are showing EDSM { tip = sc.DisplayString(historicmatlist: curmats, currentmatlist: hl.GetLast?.MaterialCommodity); if (sn.Signals != null) { tip += "\n" + "Signals".T(EDTx.ScanDisplayUserControl_Signals) + ":\n" + JournalSAASignalsFound.SignalList(sn.Signals, 4, "\n"); } if (sn.type == StarScan.ScanNodeType.ring) { } else if (sc.IsStar && toplevel) { var starLabel = sn.customname ?? sn.ownname; var habZone = sc.GetHabZoneStringLs(); if (!string.IsNullOrEmpty(habZone)) { starLabel += $" ({habZone})"; } endpoint = CreateImageLabel(pc, sc.GetStarTypeImage(), new Point(curpos.X + offset, curpos.Y + alignv), // WE are basing it on a 1/4 + 1 + 1/4 grid, this is not being made bigger, move off size, starLabel, tip, alignv + labelvoff, sc.IsEDSMBody, false); // and the label needs to be a quarter height below it.. offset += size.Width / 2; // return the middle used was this.. } else //else not a top-level star { bool indicatematerials = sc.HasMaterials && !ShowMaterials; bool valuable = sc.EstimatedValue >= ValueLimit; Image nodeimage = sc.IsStar ? sc.GetStarTypeImage() : sc.GetPlanetClassImage(); if (ImageRequiresAnOverlay(sc, indicatematerials, valuable, sn)) { Bitmap bmp = new Bitmap(size.Width * 2, quarterheight * 6); using (Graphics g = Graphics.FromImage(bmp)) { g.DrawImage(nodeimage, size.Width / 2, quarterheight, size.Width, size.Height); if (sc.IsLandable) { g.DrawImage(Icons.Controls.Scan_Bodies_Landable, new Rectangle(quarterheight, 0, quarterheight * 6, quarterheight * 6)); } if (sc.HasRings) { g.DrawImage(sc.Rings.Count() > 1 ? Icons.Controls.Scan_Bodies_RingGap : Icons.Controls.Scan_Bodies_RingOnly, new Rectangle(-2, quarterheight, size.Width * 2, size.Height)); } if (ShowOverlays) { int overlaystotal = (sc.Terraformable ? 1 : 0) + (sc.HasMeaningfulVolcanism ? 1 : 0) + (valuable ? 1 : 0) + (sc.Mapped ? 1 : 0) + (sn.Signals != null ? 1: 0); int ovsize = (overlaystotal > 1) ? quarterheight : (quarterheight * 3 / 2); int pos = 0; if (sc.Terraformable) { g.DrawImage(Icons.Controls.Scan_Bodies_Terraformable, new Rectangle(0, pos, ovsize, ovsize)); pos += ovsize + 1; } if (sc.HasMeaningfulVolcanism) //this renders below the terraformable icon if present { g.DrawImage(Icons.Controls.Scan_Bodies_Volcanism, new Rectangle(0, pos, ovsize, ovsize)); pos += ovsize + 1; } if (valuable) { g.DrawImage(Icons.Controls.Scan_Bodies_HighValue, new Rectangle(0, pos, ovsize, ovsize)); pos += ovsize + 1; } if (sc.Mapped) { g.DrawImage(Icons.Controls.Scan_Bodies_Mapped, new Rectangle(0, pos, ovsize, ovsize)); pos += ovsize + 1; } if (sn.Signals != null) { g.DrawImage(Icons.Controls.Scan_Bodies_Signals, new Rectangle(0, pos, ovsize, ovsize)); } } if (indicatematerials) { Image mm = Icons.Controls.Scan_Bodies_MaterialMore; g.DrawImage(mm, new Rectangle(bmp.Width - mm.Width, bmp.Height - mm.Height, mm.Width, mm.Height)); } } var nodeLabel = sn.customname ?? sn.ownname; if (sn.ScanData.IsLandable && sn.ScanData.nSurfaceGravity != null) { nodeLabel += $" ({(sn.ScanData.nSurfaceGravity / JournalScan.oneGee_m_s2):N2}g)"; } endpoint = CreateImageLabel(pc, bmp, curpos, new Size(bmp.Width, bmp.Height), nodeLabel, tip, labelvoff, sc.IsEDSMBody); offset = size.Width; // return that the middle is now this } else { endpoint = CreateImageLabel(pc, nodeimage, new Point(curpos.X + offset, curpos.Y + alignv), size, sn.customname ?? sn.ownname, tip, alignv + labelvoff, sc.IsEDSMBody, false); offset += size.Width / 2; } if (sc.HasMaterials && ShowMaterials) { Point matpos = new Point(endpoint.X + 4, curpos.Y); Point endmat = CreateMaterialNodes(pc, sc, curmats, hl, matpos, materialsize); endpoint = new Point(Math.Max(endpoint.X, endmat.X), Math.Max(endpoint.Y, endmat.Y)); // record new right point.. } } } else if (sn.type == StarScan.ScanNodeType.belt) { if (sn.BeltData != null) { tip = sn.BeltData.RingInformationMoons(true); } else { tip = sn.ownname + Environment.NewLine + Environment.NewLine + "No scan data available".T(EDTx.ScanDisplayUserControl_NSD); } if (sn.children != null && sn.children.Count != 0) { foreach (StarScan.ScanNode snc in sn.children.Values) { if (snc.ScanData != null) { tip += "\n\n" + snc.ScanData.DisplayString(); } } } endpoint = CreateImageLabel(pc, Icons.Controls.Scan_Bodies_Belt, new Point(curpos.X, curpos.Y + alignv), new Size(size.Width, size.Height), sn.ownname, tip, alignv + labelvoff, false, false); offset += size.Width; } else { if (sn.type == StarScan.ScanNodeType.barycentre) { tip = string.Format("Barycentre of {0}".T(EDTx.ScanDisplayUserControl_BC), sn.ownname); } else { tip = sn.ownname + Environment.NewLine + Environment.NewLine + "No scan data available".T(EDTx.ScanDisplayUserControl_NSD); } endpoint = CreateImageLabel(pc, notscanned, new Point(curpos.X + offset, curpos.Y + alignv), size, sn.customname ?? sn.ownname, tip, alignv + labelvoff, false, false); offset += size.Width / 2; // return the middle used was this.. } return(endpoint); }