#if FLEET || TESTS using System; using System.Collections.Generic; using VRageMath; namespace AutoMiningScript { public partial class Program { public partial class Dashboard { sealed class RegionView { public Vector3D Center, Up, Right; public double Extent = 1, Area; public bool Search; public int Total, Complete, Scanned, Rays, Sampled, Empty, Unknown; public readonly bool[] Cells = new bool[576]; public readonly List Dots = new List(); public readonly List Rocks = new List(); public readonly Dictionary RockIds = new Dictionary(); public Vector2 Project(Vector3D point) { var d = point-Center; return new Vector2((float)Data.Dot(d,Right),(float)Data.Dot(d,Up)); } public Vector2 Size(ScanRecord rock) => new Vector2((float)(Math.Abs(Right.X)*rock.Size.X+Math.Abs(Right.Y)*rock.Size.Y+Math.Abs(Right.Z)*rock.Size.Z), (float)(Math.Abs(Up.X)*rock.Size.X+Math.Abs(Up.Y)*rock.Size.Y+Math.Abs(Up.Z)*rock.Size.Z)); public void Rock(ScanRecord rock) { if (rock.Asteroid == 0) return; int index; if (RockIds.TryGetValue(rock.Asteroid,out index)) { if (!rock.Sized) return; var old = Rocks[index]; var size = Size(old); Area -= (double)size.X*size.Y; if (!old.Sized) Unknown--; Rocks[index] = rock; } else { RockIds.Add(rock.Asteroid,Rocks.Count); Rocks.Add(rock); if (!rock.Sized) Unknown++; } var next = Size(rock); Area += (double)next.X*next.Y; } // Raster cells mean "a ray crossed here", never full-cell clearance. // Clip before rasterizing: off-map parallel rays must not paint an edge. public void Ray(ScanRecord scan) { var a = Project(scan.Start); var d = Project(scan.End)-a; double lo=0,hi=1; for (int axis=0;axis<2;axis++) { double x=axis==0?a.X:a.Y, v=axis==0?d.X:d.Y; if (Math.Abs(v)<.00001) { if (Math.Abs(x)>Extent) return; continue; } double t=(-Extent-x)/v,u=(Extent-x)/v; lo=Math.Max(lo,Math.Min(t,u)); hi=Math.Min(hi,Math.Max(t,u)); } if(lo>hi)return; var start=a+d*(float)lo; var span=d*(float)(hi-lo); int steps=Math.Max(1,(int)Math.Ceiling(Math.Max(Math.Abs(span.X),Math.Abs(span.Y))*12/Extent)); for(int n=0;n<=steps;n++) { var q=start+span*((float)n/steps); int x=(int)Data.Clamp(Math.Floor((q.X/Extent+1)*12),0,23),y=(int)Data.Clamp(Math.Floor((q.Y/Extent+1)*12),0,23); Cells[y*24+x]=true; } } } Dictionary mapViews=new Dictionary(),buildingViews; List mapRegions=new List(),buildingRegions,buildingPages; List mapParts=new List(),buildingParts; List buildingSource; Job buildingFirst; int jobCursor,buildingDone,completedJobs,pageCursor; double nextJobRefresh; void RefreshJobs(RoleLogic role) { var jobs=role.GetJobs(); Job first=jobs.Count==0?null:jobs[0]; var replaced=jobs!=buildingSource || first!=buildingFirst; if(buildingViews==null && p.Nowjobs.Count) { buildingSource=jobs; buildingFirst=first; buildingViews=new Dictionary(); buildingRegions=new List();buildingPages=new List();buildingParts=new List();jobCursor=buildingDone=pageCursor=0; } int work=0; while(jobCursor value>=1e6?F(value/1e6,"0.00")+" km2":F(value,"0")+" m2"; void Map(Canvas c,List fleet,int listPage) { if(mapRegions.Count==0){c.Text(L.DisplayNoArea,22,110,.55f,Amber);return;} int page=listPage%mapRegions.Count;var id=mapRegions[page];var view=mapViews[id]; c.Text(view.Search?L.DisplayExplorationMap:L.DisplayMiningPlane,22,93,.6f,White); c.TextFit(view.Search?L.F(L.DisplayScanSummary,view.Scanned,view.Rays,view.Rocks.Count,view.Unknown):L.F(L.DisplayMapLegend,view.Sampled,view.Empty),22,120,c.Width-44,.40f,Blue); float left=22,top=147,width=c.Width-44,height=c.Height-270,bottom=top+height; var origin=new Vector2(c.Width/2,top+height/2);var scale=(float)((height-12)/(2*view.Extent)); c.Box(left,top,width,height,Panel); c.Line(new Vector2(left,origin.Y),new Vector2(left+width,origin.Y),Background); c.Line(new Vector2(origin.X,top),new Vector2(origin.X,bottom),Background); if(view.Search) { var cell=(float)(view.Extent/12)*scale; for(int n=0;n<576;n++)if(view.Cells[n])c.Box(origin.X+(n%24-12)*cell,origin.Y-(n/24-11)*cell,cell-0.4f,cell-0.4f,new Color(34,84,113)); for(int n=0;n<32;n++) { double a=n*Math.PI/16,b=(n+1)*Math.PI/16; c.Line(origin+new Vector2((float)Math.Cos(a),(float)Math.Sin(a))*(float)view.Extent*scale,origin+new Vector2((float)Math.Cos(b),(float)Math.Sin(b))*(float)view.Extent*scale,Muted); } } var dots=new HashSet(); foreach(var j in view.Dots) { var point=origin+view.Project(j.Entry)*new Vector2(scale,-scale); int cell=(int)(point.X/3)+(int)(point.Y/3)*4096; if(!dots.Add(cell))continue; c.Dot(point.X,point.Y,2,j.Outcome=="Blocked"||j.Outcome=="InvalidSample"?Red:j.Owner.Length>0?Amber:Finished(j)?Green:Muted); } var slots=new bool[32]; int start=mapParts[page]*8,end=Math.Min(view.Rocks.Count,start+8); for(int n=start;nx1&&y2>y1){c.Box(x1,y1,x2-x1,1,Amber);c.Box(x1,y2,x2-x1,1,Amber);c.Box(x1,y1,1,y2-y1,Amber);c.Box(x2,y1,1,y2-y1,Amber);} } point.X=(float)Data.Clamp(point.X,left+4,left+width-4);point.Y=(float)Data.Clamp(point.Y,top+3,bottom-3); float y=top+(n-start)*height/16;slots[16+n-start]=true; c.Line(point,new Vector2(left+width-174,y+7),Amber); c.Text("A"+(n+1)+" "+(rock.Sized?"~"+Area((double)size.X*size.Y):"?"),left+width-170,y,.36f,Amber); } // Two banks of label slots keep even co-located miners' IDs distinct. foreach(var t in fleet) { var point=origin+view.Project(t.Position)*new Vector2(scale,-scale); var outside=point.Xleft+width||point.Ybottom; point.X=(float)Data.Clamp(point.X,left+3,left+width-3);point.Y=(float)Data.Clamp(point.Y,top+3,bottom-3); int bank=point.X>origin.X?16:0,row=(int)Data.Clamp((point.Y-top)*16/height,0,15),slot=-1; for(int n=0;n<32;n++){int candidate=(bank+row+n)%32;if(!slots[candidate]){slot=candidate;break;}} if(slot<0)break;slots[slot]=true; float x=slot<16?left+5:left+width-170,y=top+(slot%16)*height/16; var color=!Fresh(t)||t.State==FlightState.Fault?Red:Blue; c.Line(point,new Vector2(slot<16?x+164:x,y+7),color); c.Text("+",point.X,point.Y,.5f,color); c.TextFit((outside?"*":"")+t.Id+(Fresh(t)?"":" / "+L.DisplayOffline),x,y,165,.36f,color); } c.TextFit(id+" "+view.Complete+"/"+view.Total+" +/- "+F(view.Extent,"0")+"m",22,bottom+8,width,.40f,White); c.TextFit(L.F(L.DisplayRockArea,Area(view.Area),view.Rocks.Count==0?0:start+1,end,view.Rocks.Count),22,bottom+28,width,.38f,Amber); c.TextFit(L.DisplayScanLegend,22,bottom+49,width,.36f,Blue); c.TextFit(L.DisplayScanCaution,22,bottom+69,width,.34f,Muted); } } } } #endif