Skip to content

Commit 1bdcddf

Browse files
authored
Feature: Traceroute - World Map / Visual Routing (#3520)
* Feature: Visual Traceroute (PoC) * Feature: Refactoring * Feature: Traceroute * Feature: Traceroute * Chore: copilot code review * Feature: Visual traceroute * Update TracerouteMapControl.xaml.cs * Update TracerouteMapControl.xaml.cs * Chore: Copilot feedback
1 parent 9d85c86 commit 1bdcddf

58 files changed

Lines changed: 2660 additions & 130 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Scripts/Create-WorldMapFromWeb.ps1

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Filepath in the resources
2+
[string]$OutFilePath = Join-Path -Path (Split-Path $PSScriptRoot -Parent) -ChildPath "Source\NETworkManager\Resources\Maps\world-map.json"
3+
[string]$CitiesOutFilePath = Join-Path -Path (Split-Path $PSScriptRoot -Parent) -ChildPath "Source\NETworkManager\Resources\Maps\world-cities.json"
4+
5+
# Resolution of the Natural Earth admin-0 countries / populated places dataset (110m, 50m or 10m - higher detail = larger file)
6+
[string]$Resolution = "50m"
7+
8+
# A city is included if it's a national capital, or its population is at least this high
9+
[int]$CityMinPopulation = 500000
10+
11+
# Download countries as plain GeoJSON (pre-converted from Natural Earth shapefiles, no TopoJSON decoding required)
12+
$GeoJson = (Invoke-WebRequest -Uri "https://raw.githubusercontent.com/martynafford/natural-earth-geojson/master/$Resolution/cultural/ne_${Resolution}_admin_0_countries.json").Content | ConvertFrom-Json
13+
14+
# Rounds [lon, lat] pairs to 2 decimal places (~1.1 km), which is enough detail for an abstract, non-navigational map
15+
function Get-RoundedRing {
16+
param($Ring)
17+
18+
$Points = [System.Collections.Generic.List[object]]::new()
19+
20+
foreach ($Point in $Ring) {
21+
$Points.Add(@([Math]::Round([double]$Point[0], 2), [Math]::Round([double]$Point[1], 2)))
22+
}
23+
24+
# Unary comma prevents PowerShell from unrolling the list when there is only a single ring/point
25+
, $Points
26+
}
27+
28+
# Keeps only the outer ring of every polygon part (holes like inland lakes are not relevant for an abstract map)
29+
function Get-OuterRings {
30+
param($Geometry)
31+
32+
$Rings = [System.Collections.Generic.List[object]]::new()
33+
34+
switch ($Geometry.type) {
35+
"Polygon" {
36+
$Rings.Add((Get-RoundedRing -Ring $Geometry.coordinates[0]))
37+
}
38+
"MultiPolygon" {
39+
foreach ($Part in $Geometry.coordinates) {
40+
$Rings.Add((Get-RoundedRing -Ring $Part[0]))
41+
}
42+
}
43+
}
44+
45+
, $Rings
46+
}
47+
48+
$Countries = [System.Collections.Generic.List[object]]::new()
49+
50+
foreach ($Feature in $GeoJson.features) {
51+
$Countries.Add([PSCustomObject]@{
52+
n = $Feature.properties.ADMIN
53+
r = Get-OuterRings -Geometry $Feature.geometry
54+
})
55+
}
56+
57+
ConvertTo-Json -InputObject $Countries -Depth 10 -Compress | Set-Content -Path $OutFilePath -Encoding utf8NoBOM
58+
59+
# Download populated places (cities) as plain GeoJSON
60+
$PlacesGeoJson = (Invoke-WebRequest -Uri "https://raw.githubusercontent.com/martynafford/natural-earth-geojson/master/$Resolution/cultural/ne_${Resolution}_populated_places_simple.json").Content | ConvertFrom-Json
61+
62+
$Cities = [System.Collections.Generic.List[object]]::new()
63+
64+
foreach ($Feature in $PlacesGeoJson.features) {
65+
$Properties = $Feature.properties
66+
67+
# Keep national capitals regardless of population, plus every other city above the threshold
68+
if ($Properties.adm0cap -ne 1 -and $Properties.pop_max -lt $CityMinPopulation) {
69+
continue
70+
}
71+
72+
$Cities.Add([PSCustomObject]@{
73+
n = $Properties.name
74+
lat = [Math]::Round([double]$Properties.latitude, 2)
75+
lon = [Math]::Round([double]$Properties.longitude, 2)
76+
})
77+
}
78+
79+
ConvertTo-Json -InputObject $Cities -Depth 5 -Compress | Set-Content -Path $CitiesOutFilePath -Encoding utf8NoBOM

Source/GlobalAssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66
[assembly: AssemblyTrademark("")]
77
[assembly: AssemblyCulture("")]
88

9-
[assembly: AssemblyVersion("2026.7.7.0")]
10-
[assembly: AssemblyFileVersion("2026.7.7.0")]
9+
[assembly: AssemblyVersion("2026.7.12.0")]
10+
[assembly: AssemblyFileVersion("2026.7.12.0")]

Source/NETworkManager.Documentation/ResourceManager.cs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,22 @@ public static class ResourceManager
1111
/// <summary>
1212
/// Static list with all resources that are used.
1313
/// </summary>
14-
public static List<ResourceInfo> List => new()
15-
{
16-
new ResourceInfo("Organizationally unique identifier", "https://standards-oui.ieee.org/oui/oui.txt",
14+
public static List<ResourceInfo> List =>
15+
[
16+
new("Organizationally unique identifier", "https://standards-oui.ieee.org/oui/oui.txt",
1717
Strings.Resource_OUI_Description),
18-
new ResourceInfo("Service names and port numbers",
18+
19+
new("Service names and port numbers",
1920
"https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml",
2021
Strings.Resource_ServiceNamePortNumber_Description),
21-
new ResourceInfo("flag-icon-css", "https://github.com/lipis/flag-icon-css",
22+
23+
new("flag-icon-css", "https://github.com/lipis/flag-icon-css",
2224
Strings.Resource_Flag_Description),
23-
new ResourceInfo("List of Top-Level-Domains", "https://data.iana.org/TLD/tlds-alpha-by-domain.txt",
24-
Strings.Resource_ListTLD_Description)
25-
};
25+
26+
new("List of Top-Level-Domains", "https://data.iana.org/TLD/tlds-alpha-by-domain.txt",
27+
Strings.Resource_ListTLD_Description),
28+
29+
new("natural-earth-geojson", "https://github.com/martynafford/natural-earth-geojson",
30+
Strings.Resource_NaturalEarth_Description)
31+
];
2632
}

Source/NETworkManager.Localization/Resources/Strings.Designer.cs

Lines changed: 69 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Source/NETworkManager.Localization/Resources/Strings.resx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,18 @@
573573
<data name="IPv6DefaultGateway" xml:space="preserve">
574574
<value>IPv6-Default-Gateway</value>
575575
</data>
576+
<data name="Map" xml:space="preserve">
577+
<value>Map</value>
578+
</data>
579+
<data name="PlusXMore" xml:space="preserve">
580+
<value>(+{0} more)</value>
581+
</data>
582+
<data name="ScrollToZoomDragToPan" xml:space="preserve">
583+
<value>Scroll = Zoom, Drag = Pan</value>
584+
</data>
585+
<data name="Unknown" xml:space="preserve">
586+
<value>Unknown</value>
587+
</data>
576588
<data name="Maximum" xml:space="preserve">
577589
<value>Maximum</value>
578590
</data>
@@ -2985,6 +2997,9 @@ Error message:
29852997
<data name="Resource_ListTLD_Description" xml:space="preserve">
29862998
<value>List of Top-Level-Domains from iana.org, which is used to query whois servers of the TLD from whois.iana.org via port 43</value>
29872999
</data>
3000+
<data name="Resource_NaturalEarth_Description" xml:space="preserve">
3001+
<value>GeoJSON conversion of Natural Earth vector map data (CC0-1.0).</value>
3002+
</data>
29883003
<data name="Resource_OUI_Description" xml:space="preserve">
29893004
<value>OUI data from ieee.org.</value>
29903005
</data>
@@ -3683,6 +3698,9 @@ Changes to this value will take effect after the application is restarted. Wheth
36833698
<data name="CheckIPGeolocation" xml:space="preserve">
36843699
<value>Check IP geolocation</value>
36853700
</data>
3701+
<data name="ShowMap" xml:space="preserve">
3702+
<value>Show map</value>
3703+
</data>
36863704
<data name="HelpMessage_CheckDNSResolver" xml:space="preserve">
36873705
<value>The DNS resolver is determined via ip-api.com.
36883706

@@ -3823,6 +3841,9 @@ Try again in a few seconds.</value>
38233841
<data name="ExpandHostView" xml:space="preserve">
38243842
<value>Expand host view</value>
38253843
</data>
3844+
<data name="ExpandMapView" xml:space="preserve">
3845+
<value>Expand map view</value>
3846+
</data>
38263847
<data name="CannotSetHostWhileRunningMessage" xml:space="preserve">
38273848
<value>Host cannot be set while other hosts are being added. Please wait until the process is complete and try again.</value>
38283849
</data>

Source/NETworkManager.Settings/GlobalStaticConfiguration.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,16 @@ public static class GlobalStaticConfiguration
3535
// status changes collapses into a single sound instead of an overlapping cacophony.
3636
public static int NotificationSoundThrottle => 3000;
3737

38+
// Tolerance for comparing two doubles (e.g. a resized panel width/height against a
39+
// known constant) that are expected to be "close enough" rather than bit-for-bit equal.
40+
public static double FloatPointFix => 1.0;
41+
3842
// Profile config
3943
public static bool Profile_TagsMatchAny => true;
4044
public static bool Profile_ExpandProfileView => true;
4145
public static double Profile_WidthCollapsed => 40;
4246
public static double Profile_DefaultWidthExpanded => 250;
4347
public static double Profile_MaxWidthExpanded => 500;
44-
public static double Profile_FloatPointFix => 1.0;
4548
public static int Profile_EncryptionKeySize => 256;
4649
public static int Profile_EncryptionIterations => 1000000;
4750

@@ -166,6 +169,9 @@ public static class GlobalStaticConfiguration
166169
public static int Traceroute_Buffer => 32;
167170
public static bool Traceroute_ResolveHostname => true;
168171
public static bool Traceroute_CheckIPApiIPGeolocation => false;
172+
public static bool Traceroute_ShowMap => true;
173+
public static bool Traceroute_ExpandMapView => true;
174+
public static double Traceroute_MapHeight => 300;
169175
public static ExportFileType Traceroute_ExportFileType => ExportFileType.Csv;
170176

171177
// Application: DNS Lookup

0 commit comments

Comments
 (0)