Skip to content

Implement StradarioApp from scratch - #1

Closed
paolobia with Copilot wants to merge 3 commits into
mainfrom
copilot/create-stradarioapp-from-scratch
Closed

Implement StradarioApp from scratch#1
paolobia with Copilot wants to merge 3 commits into
mainfrom
copilot/create-stradarioapp-from-scratch

Conversation

Copilot AI commented Apr 14, 2026

Copy link
Copy Markdown

Creates a full Avalonia 11.2.0 desktop app for generating cartographic PDF stradarios from OpenStreetMap tile data. Nothing existed in the repo beyond a README.

Stack

Avalonia 11.2.0 · SkiaSharp 2.88.8 · BruTile 4.0.0 · PdfSharpCore 1.3.65 · Newtonsoft.Json 13.0.3

Structure

  • Models/StradarioModels.csPageSize/PageOrientation/MapScale enums, TileServers (5 hardcoded OSM-compatible servers), StradarioSettings with page-dimension and km-coverage helpers, GeoRect, MapPage, StradarioProject (.stradario = plain JSON)

  • Services/GeoUtils.cs — WebMercator pixel↔geo conversions, tile index helpers, haversine. CalcOptimalZoom uses fixed 96 DPI (OSM reference), not settings.Dpi, to avoid over-zoomed renders

  • Services/MapRenderer.csTileCache backed by two ConcurrentDictionarys (hits + in-flight); failed tiles are intentionally not cached so they retry next frame. RenderMap is synchronous (SKCanvas not thread-safe); tile downloads are fire-and-forget Task.Run with 8 s timeout, calling InvalidateVisual on success

  • Services/PdfGenerator.csSortPages groups pages into latitude rows with 40% height tolerance before sorting N→S, W→E (plain lat sort breaks adjacent pages with slight misalignment). RenderTilesAsync uses SemaphoreSlim(4) to respect OSM policy. Overview zoom uses latExtent * cosLat in the denominator (not divided by cosLat) to avoid deformed rectangles

  • Services/FontResolver.csIFontResolver for PdfSharpCore on Linux; scans /usr/share/fonts, ~/.fonts, C:\Windows\Fonts; DefaultFontName is "dejavusans|false|false" (required by interface)

  • Services/CityDatabase.cs — Singleton lazy-loaded from cities500.csv (GeoNames format). Custom CSV parser handles quoted numeric fields. Describe() returns top-N cities by population within a GeoRect

  • UI/MapCanvas.cs — Custom Control (no external SkiaSharp-Avalonia package); hooks into ISkiaSharpApiLeaseFeature via ICustomDrawOperation.Render:

    var leaseFeature = context.TryGetFeature(typeof(ISkiaSharpApiLeaseFeature))
                           as ISkiaSharpApiLeaseFeature;
    using var lease = leaseFeature.Lease();
    _render(lease.SkCanvas, w, h);

    Posts InvalidateVisual at Background priority for continuous tile-driven redraws

  • UI/MainWindow.cs — Code-only layout with toolbar, scrollable page list, and map canvas. Pan uses TileYToLat on the translated tile-Y coordinate (correct non-linear Mercator), not a linear lat offset. Uses StorageProvider.OpenFilePickerAsync / SaveFilePickerAsync (Avalonia 11 API). Unsaved-changes guard is fully async for both window close and New/Open actions

  • UI/SettingsWindow.cs — Combos for format/orientation/DPI/scale/server with live km-coverage preview; BuildSettingsFromControls() reconstructs StradarioSettings from indices

  • UI/EditPageWindow.cs — Accepts both . and , as decimal separator; "📍 Città principali" button calls CityDatabase.Describe against the computed page bounds

  • UI/ProgressWindow.csWindow.Close() is non-virtual; uses SafeClose() pattern (sets _allowClose flag before calling base.Close()) to bypass the Closing guard

  • Program.csFontResolver.Register() before anything, CityDatabase.EnsureLoaded() on Task.Run, FluentTheme + ThemeVariant.Light (prevents illegible white text on Windows dark mode)

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • av-build-tel-api-v1.avaloniaui.net
    • Triggering command: /usr/share/dotnet/dotnet dotnet exec --runtimeconfig /home/REDACTED/.nuget/packages/avalonia.buildservices/0.0.29/tools/netstandard2.0/runtimeconfig.json /home/REDACTED/.nuget/packages/avalonia.buildservices/0.0.29/tools/netstandard2.0/Avalonia.BuildServices.Collector.dll (dns block)
    • Triggering command: /usr/share/dotnet/dotnet dotnet exec --runtimeconfig /home/REDACTED/.nuget/packages/avalonia.buildservices/0.0.29/tools/netstandard2.0/runtimeconfig.json /home/REDACTED/.nuget/packages/avalonia.buildservices/0.0.29/tools/netstandard2.0/Avalonia.BuildServices.Collector.dll 0 -j ACCEPT (dns block)
    • Triggering command: /usr/share/dotnet/dotnet dotnet exec --runtimeconfig /home/REDACTED/.nuget/packages/avalonia.buildservices/0.0.29/tools/netstandard2.0/runtimeconfig.json /home/REDACTED/.nuget/packages/avalonia.buildservices/0.0.29/tools/netstandard2.0/Avalonia.BuildServices.Collector.dll 1 1 (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

Create StradarioApp from scratch as specified in the provided Italian prompt. Implement the exact file structure and all code requirements, using Avalonia 11.2.0, SkiaSharp 2.88.8, BruTile 4.0.0, PdfSharpCore 1.3.65, Newtonsoft.Json 13.0.3. Do not use non-existent or forbidden packages. Ensure Program.cs calls FontResolver.Register() before everything, starts CityDatabase.EnsureLoaded() in background, sets FluentTheme and RequestedThemeVariant Light. Implement Models enums, TileServers list, StradarioSettings methods, GeoRect, MapPage, StradarioProject. Implement GeoUtils WebMercator conversions and CalcOptimalZoom using fixed 96 DPI, plus tile conversion functions and haversine. Implement MapRenderer with TileCache that caches only successes and tracks in-flight downloads, HttpClient user-agent and timeout, synchronous RenderMap that draws cached tiles and fires background downloads, plus DrawPages overlay with selected style and label shadow. Implement custom MapCanvas control using Avalonia.Skia ISkiaSharpApiLeaseFeature with continuous invalidation. Implement MainWindow in code-only with toolbar, left page list, map interactions (pan/zoom/add page/drag page) per spec, StorageProvider dialogs, dirty state, closing confirm dialog, and settings integration with cache clear on server change. Implement SettingsWindow with combos, live preview, nullable combo fields, BuildSettingsFromControls. Implement EditPageWindow with coords parsing accepting ',' and '.', and button to fill description using CityDatabase.Describe and GeoUtils.CalcPageBounds. Implement ProgressWindow with using Avalonia for Thickness and safe Close override. Implement PdfGenerator with SortPages grouping tolerance, PDF structure (index, overview, pages), index table formatting, overview zoom formula with latExtent*cosLat, shared RenderTilesAsync parallel downloads with SemaphoreSlim(4), 10s tile timeout, draw only after WhenAll, and page borders (15mm margin and rotated text strips). Implement FontResolver for PdfSharpCore scanning system fonts; must implement DefaultFontName property and Register sets GlobalFontSettings.FontResolver. Implement CityDatabase loading cities500.csv from multiple locations, custom CSV parser handling quoted numeric fields, singleton/lazy load, FindTopCities and Describe.

Also implement ProjectService for load/save .stradario JSON and updating LastModified and view state. Ensure app compiles and runs on Windows/Linux. Add any minimal supporting code needed (e.g., SkiaPaintEventArgs, MapDrawOperation, helper dialogs). Do not add AXAML; everything code-only.

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: # Prompt per ricreare StradarioApp da zero

Obiettivo

Crea un'applicazione desktop C# portabile Linux/Windows chiamata StradarioApp
per creare stradari cartografici in PDF con dati OpenStreetMap.


Stack tecnologico

.csproj — versioni ESATTE, non cambiarle

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Avalonia"               Version="11.2.0" />
    <PackageReference Include="Avalonia.Desktop"       Version="11.2.0" />
    <PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.0" />
    <PackageReference Include="Avalonia.Fonts.Inter"   Version="11.2.0" />
    <PackageReference Include="Avalonia.Skia"          Version="11.2.0" />
    <PackageReference Include="SkiaSharp"              Version="2.88.8" />
    <PackageReference Include="BruTile"                Version="4.0.0"  />
    <PackageReference Include="PdfSharpCore"           Version="1.3.65" />
    <PackageReference Include="Newtonsoft.Json"        Version="13.0.3" />
  </ItemGroup>
</Project>

⚠️ Pacchetti che NON esistono — non usarli

  • SkiaSharp.Views.Avalonia → non esiste, il canvas si implementa a mano
  • Avalonia.Controls.Skia → instabile per Avalonia 11, non usare
  • BruTile.MbTiles → non necessario
  • Tutte le versioni Avalonia DEVONO essere uguali (11.2.0)

Struttura file

StradarioApp/
├── Program.cs
├── StradarioApp.csproj
├── Models/
│   └── StradarioModels.cs
├── Services/
│   ├── GeoUtils.cs
│   ├── MapRenderer.cs
│   ├── PdfGenerator.cs
│   ├── ProjectService.cs
│   ├── FontResolver.cs
│   └── CityDatabase.cs
└── UI/
    ├── MapCanvas.cs
    ├── MainWindow.cs
    ├── SettingsWindow.cs
    ├── EditPageWindow.cs
    └── ProgressWindow.cs

Program.cs

  • Chiama FontResolver.Register() PRIMA di tutto
  • Avvia CityDatabase.EnsureLoaded() in background con Task.Run()
  • Inizializza Avalonia con FluentTheme
  • Imposta RequestedThemeVariant = ThemeVariant.Light per evitare testi
    bianchi illeggibili su Windows dark mode

Models/StradarioModels.cs

Enums:

  • PageSize: A5,...

This pull request was created from Copilot chat.

Copilot AI and others added 2 commits April 14, 2026 20:54
Copilot AI changed the title [WIP] Create StradarioApp implementation with specified requirements Implement StradarioApp from scratch Apr 14, 2026
Copilot AI requested a review from paolobia April 14, 2026 21:00

@paolobia paolobia left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

@paolobia paolobia closed this Apr 14, 2026
@paolobia
paolobia deleted the copilot/create-stradarioapp-from-scratch branch July 19, 2026 20:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants