From c42faa1e2e714fb0a37d88e3011179a40a446d23 Mon Sep 17 00:00:00 2001 From: Alex Bezdieniezhnykh Date: Mon, 30 Jun 2025 00:01:20 +0300 Subject: [PATCH] add zoom and panning zoom: ctrl + wheel, zoomed image: ctrl + move mousr --- Azaion.Annotator/Annotator.xaml | 15 +++- Azaion.Annotator/Annotator.xaml.cs | 15 +++- Azaion.Common/Controls/CanvasEditor.cs | 101 +++++++++++++++++++------ Azaion.Common/DTO/SelectionState.cs | 5 +- 4 files changed, 108 insertions(+), 28 deletions(-) diff --git a/Azaion.Annotator/Annotator.xaml b/Azaion.Annotator/Annotator.xaml index f77d1fa..ab57de6 100644 --- a/Azaion.Annotator/Annotator.xaml +++ b/Azaion.Annotator/Annotator.xaml @@ -315,7 +315,7 @@ - + + diff --git a/Azaion.Annotator/Annotator.xaml.cs b/Azaion.Annotator/Annotator.xaml.cs index cd939a6..f150808 100644 --- a/Azaion.Annotator/Annotator.xaml.cs +++ b/Azaion.Annotator/Annotator.xaml.cs @@ -304,7 +304,7 @@ public partial class Annotator { if (File.Exists(annotation.ImagePath)) { - Editor.Background = new ImageBrush { ImageSource = await annotation.ImagePath.OpenImage() }; + Editor.SetImageSource(await annotation.ImagePath.OpenImage()); _formState.BackgroundTime = annotation.Time; videoSize = Editor.RenderSize; } @@ -578,10 +578,21 @@ public partial class Annotator } } + #region Denys Wishes + private void SoundDetections(object sender, RoutedEventArgs e) { - _logger.LogInformation("To be implemented"); + MessageBox.Show("Функція Аудіоаналіз знаходиться в стадії розробки","Система", MessageBoxButton.OK, MessageBoxImage.Information); + _logger.LogInformation("Denys wishes #1. To be implemented"); } + + private void RunDroneMaintenance(object sender, RoutedEventArgs e) + { + MessageBox.Show("Функція Аналіз стану БПЛА знаходиться в стадії розробки","Система", MessageBoxButton.OK, MessageBoxImage.Information); + _logger.LogInformation("Denys wishes #2. To be implemented"); + } + + #endregion } public class GradientStyleSelector : StyleSelector diff --git a/Azaion.Common/Controls/CanvasEditor.cs b/Azaion.Common/Controls/CanvasEditor.cs index 86ec997..5760db1 100644 --- a/Azaion.Common/Controls/CanvasEditor.cs +++ b/Azaion.Common/Controls/CanvasEditor.cs @@ -3,11 +3,12 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; +using System.Windows.Media.Imaging; using System.Windows.Shapes; -using Azaion.Annotator.DTO; using Azaion.Common.DTO; using MediatR; using Color = System.Windows.Media.Color; +using Image = System.Windows.Controls.Image; using Point = System.Windows.Point; using Rectangle = System.Windows.Shapes.Rectangle; using Size = System.Windows.Size; @@ -28,10 +29,15 @@ public class CanvasEditor : Canvas private Rectangle _curRec = new(); private DetectionControl _curAnn = null!; - + + private readonly MatrixTransform _matrixTransform = new(); + private Point _panStartPoint; + private bool _isZoomedIn; + private const int MIN_SIZE = 20; private readonly TimeSpan _viewThreshold = TimeSpan.FromMilliseconds(400); - + + private Image _backgroundImage { get; set; } = new() { Stretch = Stretch.Fill }; public IMediator Mediator { get; set; } = null!; public static readonly DependencyProperty GetTimeFuncProp = @@ -107,13 +113,42 @@ public class CanvasEditor : Canvas MouseUp += CanvasMouseUp; SizeChanged += CanvasResized; Cursor = Cursors.Cross; - + Children.Insert(0, _backgroundImage); Children.Add(_newAnnotationRect); Children.Add(_horizontalLine); Children.Add(_verticalLine); Children.Add(_classNameHint); Loaded += Init; + RenderTransform = _matrixTransform; + MouseWheel += CanvasWheel; + } + + public void SetImageSource(ImageSource? source) + { + _backgroundImage.Source = source; + } + + private void CanvasWheel(object sender, MouseWheelEventArgs e) + { + if (Keyboard.Modifiers != ModifierKeys.Control) + return; + + var mousePos = e.GetPosition(this); + var scale = e.Delta > 0 ? 1.1 : 1 / 1.1; + + var matrix = _matrixTransform.Matrix; + if (scale < 1 && matrix.M11 * scale < 1.0) + { + _matrixTransform.Matrix = Matrix.Identity; + _isZoomedIn = false; + } + else + { + matrix.ScaleAt(scale, scale, mousePos.X, mousePos.Y); + _matrixTransform.Matrix = matrix; + _isZoomedIn = true; + } } private void Init(object sender, RoutedEventArgs e) @@ -127,7 +162,13 @@ public class CanvasEditor : Canvas private void CanvasMouseDown(object sender, MouseButtonEventArgs e) { ClearSelections(); - NewAnnotationStart(sender, e); + if (Keyboard.Modifiers == ModifierKeys.Control && _isZoomedIn) + { + _panStartPoint = e.GetPosition(this); + SelectionState = SelectionState.PanZoomMoving; + } + else + NewAnnotationStart(sender, e); } private void CanvasMouseMove(object sender, MouseEventArgs e) @@ -137,17 +178,32 @@ public class CanvasEditor : Canvas _verticalLine.X1 = _verticalLine.X2 = pos.X; SetLeft(_classNameHint, pos.X + 10); SetTop(_classNameHint, pos.Y - 30); - - if (e.LeftButton != MouseButtonState.Pressed) - return; - if (SelectionState == SelectionState.NewAnnCreating) - NewAnnotationCreatingMove(sender, e); - - if (SelectionState == SelectionState.AnnResizing) - AnnotationResizeMove(sender, e); - if (SelectionState == SelectionState.AnnMoving) - AnnotationPositionMove(sender, e); + switch (SelectionState) + { + case SelectionState.NewAnnCreating: + NewAnnotationCreatingMove(sender, e); + break; + case SelectionState.AnnResizing: + AnnotationResizeMove(sender, e); + break; + case SelectionState.AnnMoving: + AnnotationPositionMove(sender, e); + break; + case SelectionState.PanZoomMoving: + PanZoomMove(sender, e); + break; + } + } + + private void PanZoomMove(object sender, MouseEventArgs e) + { + var currentPoint = e.GetPosition(this); + var delta = currentPoint - _panStartPoint; + + var matrix = _matrixTransform.Matrix; + matrix.Translate(delta.X, delta.Y); + _matrixTransform.Matrix = matrix; } private void CanvasMouseUp(object sender, MouseButtonEventArgs e) @@ -173,15 +229,12 @@ public class CanvasEditor : Canvas }); control.UpdateLayout(); CheckLabelBoundaries(control); - SelectionState = SelectionState.None; - e.Handled = true; } - else - { + else if (SelectionState != SelectionState.PanZoomMoving) CheckLabelBoundaries(_curAnn); - SelectionState = SelectionState.None; - e.Handled = true; - } + + SelectionState = SelectionState.None; + e.Handled = true; } private void CheckLabelBoundaries(DetectionControl detectionControl) @@ -213,6 +266,8 @@ public class CanvasEditor : Canvas { _horizontalLine.X2 = e.NewSize.Width; _verticalLine.Y2 = e.NewSize.Height; + _backgroundImage.Width = e.NewSize.Width; + _backgroundImage.Height = e.NewSize.Height; } #region Annotation Resizing & Moving @@ -319,7 +374,7 @@ public class CanvasEditor : Canvas SetLeft(_newAnnotationRect, _newAnnotationStartPos.X); SetTop(_newAnnotationRect, _newAnnotationStartPos.Y); _newAnnotationRect.MouseMove += NewAnnotationCreatingMove; - + SelectionState = SelectionState.NewAnnCreating; } diff --git a/Azaion.Common/DTO/SelectionState.cs b/Azaion.Common/DTO/SelectionState.cs index a892f27..4bd3fd5 100644 --- a/Azaion.Common/DTO/SelectionState.cs +++ b/Azaion.Common/DTO/SelectionState.cs @@ -1,9 +1,10 @@ -namespace Azaion.Annotator.DTO; +namespace Azaion.Common.DTO; public enum SelectionState { None = 0, NewAnnCreating = 1, AnnResizing = 2, - AnnMoving = 3 + AnnMoving = 3, + PanZoomMoving = 4, } \ No newline at end of file