Изменение ширины повернутого UserControl приводит к переводу - PullRequest
0 голосов
/ 25 февраля 2020

Я пытаюсь создать простую коробку преобразования. Я начал добавлять изменение размера (в настоящее время только расширение ширины справа), но когда я изменяю ширину, а затем поворачиваюсь, перевод Y портится. Я полагаю, что перевод Y должен меняться в зависимости от поворота, чтобы манипуляции выглядели согласованно, но по какой-то причине я не могу понять, как это учитывать. 1004 *

(следующий UserControl является дочерним элементом элемента управления Canvas)

.xaml

<UserControl
    x:Class="TransformBox"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    PointerPressed="UserControl_PointerPressed"
    PointerMoved="UserControl_PointerMoved"
    PointerReleased="UserControl_PointerReleased"
    Width="200" Height="150">
    <UserControl.Resources>
        <Style x:Key="ScaleEllipseStyle" TargetType="Ellipse">
            <Setter Property="Width" Value="12"/>
            <Setter Property="Height" Value="12"/>
            <Setter Property="Fill" Value="{StaticResource SystemAccentColor}"/>
        </Style>
    </UserControl.Resources>

    <Grid>
        <Rectangle x:Name="RotateRegion" Stroke="Purple" StrokeThickness="20" Margin="-20"/>
        <Rectangle x:Name="TranslateRegion" Fill="Transparent" StrokeThickness="2"/>
        <Ellipse Style="{StaticResource ScaleEllipseStyle}" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="-6,-6,0,0"/>
        <Ellipse Style="{StaticResource ScaleEllipseStyle}" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,-6,0,0"/>
        <Ellipse Style="{StaticResource ScaleEllipseStyle}" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,-6,-6,0"/>
        <Ellipse Style="{StaticResource ScaleEllipseStyle}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="-6,0,0,0"/>
        <Ellipse Style="{StaticResource ScaleEllipseStyle}" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,-6,0"/>
        <Ellipse Style="{StaticResource ScaleEllipseStyle}" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="-6,0,0,-6"/>
        <Ellipse Style="{StaticResource ScaleEllipseStyle}" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,-6"/>
        <Ellipse Style="{StaticResource ScaleEllipseStyle}" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,-6,-6"/>
        <Ellipse x:Name="OriginRegion" Width="12" Height="12" Fill="Transparent" Stroke="{StaticResource SystemAccentColor}" StrokeThickness="2"/>
    </Grid>
</UserControl>

.xaml.cs

public sealed partial class TransformBox : UserControl
{
   private bool isDragging;
   private Point prevPosition;
   private Point _clickPosition;
   private TransformType action;
   private double _prevRot = 0;
   public float SetWidth = 200;
   public float SetHeight = 150;
   public Point Origin = new Point(0.5, 0.5);
   public float X = 0;
   public float Y = 0;
   public new float Rotation = 0;

   public TransformBox()
   {
       this.InitializeComponent();
       Width = SetWidth;
       Height = SetHeight;
   }

   private void UserControl_PointerPressed(object sender, PointerRoutedEventArgs e)
   {
       isDragging = true;
       _clickPosition = prevPosition = e.GetCurrentPoint(Parent as UIElement).Position;
       this.CapturePointer(e.Pointer);

       if (e.OriginalSource == TranslateRegion) {
           action = TransformType.Translate;
       }
       else if (e.OriginalSource == RotateRegion)
       {
           action = TransformType.Rotate;
           _prevRot = Math.Atan2(_clickPosition.Y - (Y + Height / 2), _clickPosition.X - (X + Width / 2));
       }
       else if (e.OriginalSource == OriginRegion)
       {
           action = TransformType.TransformOrigin;
       } 
       else
       {
           action = TransformType.Scale;
       }
   }

   private void UserControl_PointerMoved(object sender, PointerRoutedEventArgs e)
   {
       if (isDragging)
       {
           Point mousePos = e.GetCurrentPoint(Parent as UIElement).Position;
           switch (action)
           {
               case TransformType.Translate:
                   X += (float) (mousePos.X - prevPosition.X);
                   Y += (float) (mousePos.Y - prevPosition.Y);
                   prevPosition = mousePos;
                   break;

               case TransformType.Rotate:
                   double curRot = Math.Atan2(mousePos.Y - (Y + Height / 2), mousePos.X - (X + Width / 2));
                   Rotation += (float) (curRot - _prevRot);
                   _prevRot = curRot;
                   break;

               case TransformType.Scale:
                   double dist = Math.Sqrt(Math.Pow(mousePos.X - _clickPosition.X, 2) + Math.Pow(mousePos.Y - _clickPosition.Y, 2) * 1.0);
                   double mouseRot = Math.Atan2(mousePos.Y - _clickPosition.Y, mousePos.X - _clickPosition.X);
                   double proj = dist * Math.Cos(0 - mouseRot);
                   Width = SetWidth + proj;
                   break;
           }

           Matrix4x4 translate = Matrix4x4.CreateTranslation(new Vector3(X, Y, 0f));
           Matrix4x4 rotate = Matrix4x4.CreateRotationZ(Rotation, new Vector3(X + (float) SetWidth / 2, Y + (float) SetHeight / 2, 0f));
           TransformMatrix = Matrix4x4.Multiply(translate, rotate);
       }
   }

   private void UserControl_PointerReleased(object sender, PointerRoutedEventArgs e)
   {
       isDragging = false;
       SetWidth = (float) Width;
       SetHeight = (float) Height;
       this.ReleasePointerCapture(e.Pointer);
   }

   enum TransformType
   {
       Translate,
       Rotate,
       Scale,
       TransformOrigin
   }
}

1 Ответ

0 голосов
/ 27 февраля 2020

В любом случае попробуйте скомпенсировать смещение центра вращения в обработчике событий PointerReleased.

private void UserControl_PointerReleased(object sender, PointerRoutedEventArgs e)
{
   isDragging = false;

   double deltaCentreX = 0.5 * (Width - SetWidth);
   double deltaCentreY = 0.5 * (Height - SetHeight);
   X -= (float)((1.0 - Math.Cos(Rotation)) * deltaCentreX + Math.Sin(Rotation) * deltaCentreY);
   Y -= (float)(-Math.Sin(Rotation) * deltaCentreX + (1.0 - Math.Cos(Rotation)) * deltaCentreY);

   SetWidth = (float) Width;
   SetHeight = (float) Height;
   this.ReleasePointerCapture(e.Pointer);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...