commit 0d108223f9bd567312b4615acd9185ae56ad6d51 Author: ti_mo Date: Mon Oct 20 19:55:15 2025 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..add57be --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +bin/ +obj/ +/packages/ +riderModule.iml +/_ReSharper.Caches/ \ No newline at end of file diff --git a/DelauneyTriangulation.sln b/DelauneyTriangulation.sln new file mode 100644 index 0000000..4939236 --- /dev/null +++ b/DelauneyTriangulation.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DelauneyTriangulation", "DelauneyTriangulation\DelauneyTriangulation.csproj", "{2A9A87E7-EE9E-4D2C-840D-C5BD1E979CDB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2A9A87E7-EE9E-4D2C-840D-C5BD1E979CDB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A9A87E7-EE9E-4D2C-840D-C5BD1E979CDB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A9A87E7-EE9E-4D2C-840D-C5BD1E979CDB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A9A87E7-EE9E-4D2C-840D-C5BD1E979CDB}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/DelauneyTriangulation/App.axaml b/DelauneyTriangulation/App.axaml new file mode 100644 index 0000000..88324c6 --- /dev/null +++ b/DelauneyTriangulation/App.axaml @@ -0,0 +1,15 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/DelauneyTriangulation/App.axaml.cs b/DelauneyTriangulation/App.axaml.cs new file mode 100644 index 0000000..d225297 --- /dev/null +++ b/DelauneyTriangulation/App.axaml.cs @@ -0,0 +1,33 @@ +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Data.Core; +using Avalonia.Data.Core.Plugins; +using Avalonia.Markup.Xaml; +using DelauneyTriangulation.ViewModels; +using DelauneyTriangulation.Views; + +namespace DelauneyTriangulation; + +public partial class App : Application +{ + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + } + + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + // Line below is needed to remove Avalonia data validation. + // Without this line you will get duplicate validations from both Avalonia and CT + BindingPlugins.DataValidators.RemoveAt(0); + desktop.MainWindow = new MainWindow + { + DataContext = new MainWindowViewModel(), + }; + } + + base.OnFrameworkInitializationCompleted(); + } +} \ No newline at end of file diff --git a/DelauneyTriangulation/Assets/avalonia-logo.ico b/DelauneyTriangulation/Assets/avalonia-logo.ico new file mode 100644 index 0000000..da8d49f Binary files /dev/null and b/DelauneyTriangulation/Assets/avalonia-logo.ico differ diff --git a/DelauneyTriangulation/DelauneyTriangulation.csproj b/DelauneyTriangulation/DelauneyTriangulation.csproj new file mode 100644 index 0000000..d0397d6 --- /dev/null +++ b/DelauneyTriangulation/DelauneyTriangulation.csproj @@ -0,0 +1,24 @@ + + + WinExe + net9.0 + enable + true + app.manifest + true + + + + + + + + + + + + + + + + diff --git a/DelauneyTriangulation/Models/Geometries.cs b/DelauneyTriangulation/Models/Geometries.cs new file mode 100644 index 0000000..61934a9 --- /dev/null +++ b/DelauneyTriangulation/Models/Geometries.cs @@ -0,0 +1,39 @@ +using Avalonia; + +namespace DelauneyTriangulation.Models; + +public class Geometries +{ + public sealed class GeomPoint(double x, double y, double z = 3) + { + public double X { get; } = x; + public double Y { get; } = y; + public double R { get; } = z; + + public double Left => X - R; + public double Top => Y - R; + public double Size => 2 * R; + } + + public sealed class GeomEdge(double x1, double y1, double x2, double y2) + { + public double X1 { get; } = x1; + public double X2 { get; } = x2; + public double Y1 { get; } = y1; + public double Y2 { get; } = y2; + + public Point Start => new(X1, Y1); + public Point End => new(X2, Y2); + } + + public sealed class GeomCircle(double x, double y, double r) + { + public double X { get; } = x; + public double Y { get; } = y; + public double R { get; } = r; + + public double Left => X - R; + public double Top => Y - R; + public double Diameter => 2 * R; + } +} \ No newline at end of file diff --git a/DelauneyTriangulation/Program.cs b/DelauneyTriangulation/Program.cs new file mode 100644 index 0000000..0880058 --- /dev/null +++ b/DelauneyTriangulation/Program.cs @@ -0,0 +1,21 @@ +using Avalonia; +using System; + +namespace DelauneyTriangulation; + +sealed class Program +{ + // Initialization code. Don't use any Avalonia, third-party APIs or any + // SynchronizationContext-reliant code before AppMain is called: things aren't initialized + // yet and stuff might break. + [STAThread] + public static void Main(string[] args) => BuildAvaloniaApp() + .StartWithClassicDesktopLifetime(args); + + // Avalonia configuration, don't remove; also used by visual designer. + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .UsePlatformDetect() + .WithInterFont() + .LogToTrace(); +} \ No newline at end of file diff --git a/DelauneyTriangulation/ViewLocator.cs b/DelauneyTriangulation/ViewLocator.cs new file mode 100644 index 0000000..f1ed25b --- /dev/null +++ b/DelauneyTriangulation/ViewLocator.cs @@ -0,0 +1,32 @@ +using System; +using Avalonia.Controls; +using Avalonia.Controls.Templates; +using DelauneyTriangulation.ViewModels; + +namespace DelauneyTriangulation; + +public class ViewLocator : IDataTemplate +{ + public Control? Build(object? data) + { + if (data is null) + return null; + + var name = data.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal); + var type = Type.GetType(name); + + if (type != null) + { + var control = (Control)Activator.CreateInstance(type)!; + control.DataContext = data; + return control; + } + + return new TextBlock { Text = "Not Found: " + name }; + } + + public bool Match(object? data) + { + return data is ViewModelBase; + } +} \ No newline at end of file diff --git a/DelauneyTriangulation/ViewModels/MainWindowViewModel.cs b/DelauneyTriangulation/ViewModels/MainWindowViewModel.cs new file mode 100644 index 0000000..703b3ee --- /dev/null +++ b/DelauneyTriangulation/ViewModels/MainWindowViewModel.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.ObjectModel; +using System.ComponentModel; +using CommunityToolkit.Mvvm.ComponentModel; +using DelauneyTriangulation.Models; + +namespace DelauneyTriangulation.ViewModels; + +public partial class MainWindowViewModel : ViewModelBase +{ + [ObservableProperty] private int _pointCount = 20; + [ObservableProperty] private double _panX; + [ObservableProperty] private double _panY; + [ObservableProperty] private double _zoom = 1.0; + public double Width { get; set; } = 1280; + public double Height { get; set; } = 720; + + public ObservableCollection Points { get; } = new(); + public ObservableCollection Edges { get; } = new(); + public ObservableCollection Circles { get; } = new(); + + public MainWindowViewModel() + { + var rand = new Random(); + + for (int i = 0; i < PointCount; i++) + { + double x = rand.NextDouble() * Width; + double y = rand.NextDouble() * Height; + Points.Add(new Geometries.GeomPoint(x, y)); + } + } +} \ No newline at end of file diff --git a/DelauneyTriangulation/ViewModels/ViewModelBase.cs b/DelauneyTriangulation/ViewModels/ViewModelBase.cs new file mode 100644 index 0000000..b09bd87 --- /dev/null +++ b/DelauneyTriangulation/ViewModels/ViewModelBase.cs @@ -0,0 +1,7 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace DelauneyTriangulation.ViewModels; + +public class ViewModelBase : ObservableObject +{ +} \ No newline at end of file diff --git a/DelauneyTriangulation/Views/MainWindow.axaml b/DelauneyTriangulation/Views/MainWindow.axaml new file mode 100644 index 0000000..93bbcd7 --- /dev/null +++ b/DelauneyTriangulation/Views/MainWindow.axaml @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DelauneyTriangulation/Views/MainWindow.axaml.cs b/DelauneyTriangulation/Views/MainWindow.axaml.cs new file mode 100644 index 0000000..21883c3 --- /dev/null +++ b/DelauneyTriangulation/Views/MainWindow.axaml.cs @@ -0,0 +1,69 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Shapes; +using Avalonia.Input; +using Avalonia.Interactivity; +using Avalonia.Media; + +namespace DelauneyTriangulation.Views; + +public partial class MainWindow : Window +{ + private bool _isPanning; + private Point _panStart; + private Vector _panOffset = new(); + private readonly TranslateTransform _panTransform = new(); + + public MainWindow() + { + InitializeComponent(); + SceneContent.RenderTransform = _panTransform; + } + + private void OnTitleBarPointerPressed(object? sender, PointerPressedEventArgs e) + { + if (!e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) return; + BeginMoveDrag(e); + } + private void OnTitleBarDoubleTapped(object? sender, RoutedEventArgs e) => WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; + private void Scene_OnPointerPressed(object? sender, PointerPressedEventArgs e) + { + if (!e.GetCurrentPoint(Scene).Properties.IsLeftButtonPressed) + return; + + _isPanning = true; + _panStart = e.GetPosition(this); + Scene.Cursor = new Cursor(StandardCursorType.SizeAll); + e.Handled = true; + } + + private void Scene_OnPointerMoved(object? sender, PointerEventArgs e) + { + if (!_isPanning) return; + + var pos = e.GetPosition(this); + var delta = pos - _panStart; + var current = _panOffset + delta; + _panTransform.X = current.X; + _panTransform.Y = current.Y; + e.Handled = true; + } + + private void Scene_OnPointerReleased(object? sender, PointerReleasedEventArgs e) + { + if (!_isPanning) return; + + var pos = e.GetPosition(this); + var delta = pos - _panStart; + _panOffset += delta; + + _isPanning = false; + Scene.Cursor = new Cursor(StandardCursorType.Arrow); + e.Handled = true; + } + + private void Scene_OnWheel(object? sender, PointerWheelEventArgs e) + { + + } +} \ No newline at end of file diff --git a/DelauneyTriangulation/app.manifest b/DelauneyTriangulation/app.manifest new file mode 100644 index 0000000..5d23698 --- /dev/null +++ b/DelauneyTriangulation/app.manifest @@ -0,0 +1,18 @@ + + + + + + + + + + + + + +