diff --git a/LensSimulator.sln b/LensSimulator.sln index 46f7768..deaf39f 100644 --- a/LensSimulator.sln +++ b/LensSimulator.sln @@ -9,7 +9,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImplementationTest", "Imple EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LensSimulatorWindows", "LensSimulatorWindows\LensSimulatorWindows.csproj", "{ACDB5AA7-0C3D-4923-9843-E850C3807041}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LensSimulator-WinForms", "LensSimulator-WinForms\LensSimulator-WinForms.csproj", "{F16F2F39-B341-4591-8D1E-A0BAC484248E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LensSimulator-WinForms", "LensSimulator-WinForms\LensSimulator-WinForms.csproj", "{F16F2F39-B341-4591-8D1E-A0BAC484248E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LensSimulatorWPF", "LensSimulatorWPF\LensSimulatorWPF.csproj", "{0C57DE67-4CA1-4F8D-9D9F-9DF8FD1C87E1}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -33,6 +35,10 @@ Global {F16F2F39-B341-4591-8D1E-A0BAC484248E}.Debug|Any CPU.Build.0 = Debug|Any CPU {F16F2F39-B341-4591-8D1E-A0BAC484248E}.Release|Any CPU.ActiveCfg = Release|Any CPU {F16F2F39-B341-4591-8D1E-A0BAC484248E}.Release|Any CPU.Build.0 = Release|Any CPU + {0C57DE67-4CA1-4F8D-9D9F-9DF8FD1C87E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C57DE67-4CA1-4F8D-9D9F-9DF8FD1C87E1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0C57DE67-4CA1-4F8D-9D9F-9DF8FD1C87E1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0C57DE67-4CA1-4F8D-9D9F-9DF8FD1C87E1}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/LensSimulatorWPF/App.xaml b/LensSimulatorWPF/App.xaml new file mode 100644 index 0000000..e13ffaa --- /dev/null +++ b/LensSimulatorWPF/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/LensSimulatorWPF/App.xaml.cs b/LensSimulatorWPF/App.xaml.cs new file mode 100644 index 0000000..221bbce --- /dev/null +++ b/LensSimulatorWPF/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace LensSimulatorWPF +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/LensSimulatorWPF/AssemblyInfo.cs b/LensSimulatorWPF/AssemblyInfo.cs new file mode 100644 index 0000000..8b5504e --- /dev/null +++ b/LensSimulatorWPF/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/LensSimulatorWPF/LensSimulatorWPF.csproj b/LensSimulatorWPF/LensSimulatorWPF.csproj new file mode 100644 index 0000000..d84276c --- /dev/null +++ b/LensSimulatorWPF/LensSimulatorWPF.csproj @@ -0,0 +1,10 @@ + + + + WinExe + net7.0-windows + enable + true + + + diff --git a/LensSimulatorWPF/LensSimulatorWPF.csproj.user b/LensSimulatorWPF/LensSimulatorWPF.csproj.user new file mode 100644 index 0000000..644b0a6 --- /dev/null +++ b/LensSimulatorWPF/LensSimulatorWPF.csproj.user @@ -0,0 +1,14 @@ + + + + + + Designer + + + + + Designer + + + \ No newline at end of file diff --git a/LensSimulatorWPF/MainWindow.xaml b/LensSimulatorWPF/MainWindow.xaml new file mode 100644 index 0000000..927a5a7 --- /dev/null +++ b/LensSimulatorWPF/MainWindow.xaml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + diff --git a/LensSimulatorWPF/MainWindow.xaml.cs b/LensSimulatorWPF/MainWindow.xaml.cs new file mode 100644 index 0000000..64b5999 --- /dev/null +++ b/LensSimulatorWPF/MainWindow.xaml.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace LensSimulatorWPF +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + private Point _lastDragPoint; + private Matrix _currentMatrix = Matrix.Identity; + private const double ScaleRate = 1.1; + private const double MinScale = 0.5; + private const double MaxScale = 10.0; + + private Point lastZoomPos = new Point(0, 0); + + public MainWindow() + { + InitializeComponent(); + DrawGrid(); + this.MouseWheel += MainWindow_MouseWheel; + this.MouseLeftButtonDown += MainWindow_MouseLeftButtonDown; + this.MouseLeftButtonUp += MainWindow_MouseLeftButtonUp; + this.MouseMove += MainWindow_MouseMove; + } + + private void MainWindow_MouseWheel(object sender, MouseWheelEventArgs e) + { + var scale = e.Delta > 0 ? ScaleRate : 1 / ScaleRate; + + // Clamp the scale in between the min and max scale + if (_currentMatrix.M11 * scale < MinScale || _currentMatrix.M11 * scale > MaxScale) + { + return; + } + + // Get the mouse position in screen space (relative to canvas) + var screenMousePos = e.GetPosition(canvas); + + // Convert the screen mouse position to the canvas space + var matrix = _currentMatrix; + matrix.Invert(); + + var targetPointInCanvas = matrix.Transform(screenMousePos); + + lastZoomPos = targetPointInCanvas; + + // Perform the scale operation at the target point + _currentMatrix.ScaleAtPrepend(scale, scale, canvas.ActualWidth/2, canvas.ActualHeight/ 2); + + // Apply the transformation to the canvas + canvas.RenderTransform = new MatrixTransform(_currentMatrix); + + DrawGrid(); + } + + + private void DrawGrid() + { + canvas.Children.Clear(); + + double step = 50; // The M11 component of the matrix represents the scale in X + double width = canvas.ActualWidth; + double height = canvas.ActualHeight; + + for (double i = step; i < width; i += step) + { + canvas.Children.Add(new Line + { + Stroke = Brushes.LightGray, + X1 = i, + Y1 = 0, + X2 = i, + Y2 = height + }); + } + + for (double i = step; i < height; i += step) + { + canvas.Children.Add(new Line + { + Stroke = Brushes.LightGray, + X1 = 0, + Y1 = i, + X2 = width, + Y2 = i + }); + } + + var ellipse = new Ellipse + { + Fill = Brushes.Red, + Width = 10, + Height = 10 + }; + + Canvas.SetLeft(ellipse, lastZoomPos.X - ellipse.Width / 2); + Canvas.SetTop(ellipse, lastZoomPos.Y - ellipse.Height / 2); + + canvas.Children.Add(ellipse); + } + + private void MainWindow_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + var mousePos = e.GetPosition(this); + _lastDragPoint = new Point(mousePos.X - _currentMatrix.OffsetX, mousePos.Y - _currentMatrix.OffsetY); + Mouse.Capture(this); + } + + private void MainWindow_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + Mouse.Capture(null); + } + + private void MainWindow_MouseMove(object sender, MouseEventArgs e) + { + if (e.LeftButton == MouseButtonState.Pressed) + { + var posNow = e.GetPosition(this); + + var deltaX = posNow.X - _lastDragPoint.X - _currentMatrix.OffsetX; + var deltaY = posNow.Y - _lastDragPoint.Y - _currentMatrix.OffsetY; + + _currentMatrix.Translate(deltaX, deltaY); + canvas.RenderTransform = new MatrixTransform(_currentMatrix); + _lastDragPoint = new Point(posNow.X - _currentMatrix.OffsetX, posNow.Y - _currentMatrix.OffsetY); + } + } + } +} \ No newline at end of file