调整翻转和旋转图像的大小

时间:2016-08-19 12:54:10

标签: c# wpf transform

所以我开始从http://www.codeproject.com/Articles/22952/WPF-Diagram-Designer-Part开始查看并构建MoveResizeRotate项目。

我添加了几件事:

  • 使用纵横比调整大小的功能,如果您拖动角落拇指。
  • 使用ScaleTransform在x轴上翻转ContentControl的功能 - 即ScaleX = -1。

然而,现在我在调整控件大小方面遇到了麻烦。它在旋转之前工作正常,但是当它旋转时,它似乎从中间而不是那个角/侧调整大小。当控件的ScaleX设置为-1时,这一点尤为明显。

这是ResizeThumb的代码:

namespace ResizeRotateFlip
{
    public class ResizeThumb : Thumb
    {
        private double angle;
        private Point transformOrigin;
        private ContentControl designerItem;

        public ResizeThumb()
        {
            DragStarted += new DragStartedEventHandler( this.ResizeThumb_DragStarted );
            DragDelta += new DragDeltaEventHandler( this.ResizeThumb_DragDelta );
        }

        private void ResizeThumb_DragStarted( object sender, DragStartedEventArgs e )
        {
            this.designerItem = DataContext as ContentControl;

            if( this.designerItem != null )
            {
                this.transformOrigin = this.designerItem.RenderTransformOrigin;
                RotateTransform rotateTransform = this.designerItem.RenderTransform as RotateTransform;

                if( rotateTransform != null )
                {
                    this.angle = rotateTransform.Angle * Math.PI / 180.0;
                }
                else
                {
                    this.angle = 0;
                }
            }
        }

        private void ResizeThumb_DragDelta( object sender, DragDeltaEventArgs e )
        {
            if( this.designerItem != null )
            {
                //variables
                double deltaVertical = 0, deltaHorizontal = 0;
                double newHeight = 0, newWidth = 0;

                double startHeight = this.designerItem.Height;
                double startWidth = this.designerItem.Width;

                //calculate deltas
                switch( VerticalAlignment )
                {
                    case System.Windows.VerticalAlignment.Bottom:
                        deltaVertical = Math.Min( -e.VerticalChange, this.designerItem.ActualHeight - this.designerItem.MinHeight );
                        break;
                    case System.Windows.VerticalAlignment.Top:
                        deltaVertical = Math.Min( e.VerticalChange, this.designerItem.ActualHeight - this.designerItem.MinHeight );
                        break;
                    default:
                        break;
                }
                switch( HorizontalAlignment )
                {
                    case System.Windows.HorizontalAlignment.Left:
                        deltaHorizontal = Math.Min( e.HorizontalChange, this.designerItem.ActualWidth - this.designerItem.MinWidth );
                        break;
                    case System.Windows.HorizontalAlignment.Right:
                        deltaHorizontal = Math.Min( -e.HorizontalChange, this.designerItem.ActualWidth - this.designerItem.MinWidth );
                        break;
                    default:
                        break;
                }    

                // resize
                if( dragging_from_corner() )
                {
                    newHeight = this.designerItem.Height - deltaVertical;
                    newWidth = this.designerItem.Width - deltaHorizontal;

                    if( newHeight >= 0 && newWidth >= 0 )
                    {
                        aspect_ratio_resizing( this.designerItem.Height, this.designerItem.Width, newHeight, newWidth );
                    }
                }
                else
                {
                    this.designerItem.Height -= deltaVertical;
                    this.designerItem.Width -= deltaHorizontal;
                }    

                // translate
                double verticalChange = startHeight - this.designerItem.Height;
                double horizontalChange = startWidth - this.designerItem.Width;

                TransformGroup transformGroup = designerItem.RenderTransform as TransformGroup;
                ScaleTransform scaleTransform = transformGroup.Children[(int)TransformType.ScaleTransform] as ScaleTransform;

                switch( VerticalAlignment )
                {
                    case System.Windows.VerticalAlignment.Bottom:
                        if( scaleTransform.ScaleY != -1 )
                        {
                            Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
                            Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) - verticalChange * this.transformOrigin.Y * Math.Sin( -this.angle ) );
                        }
                        else
                        {
                            Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + verticalChange * Math.Cos( -this.angle ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
                            Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) + verticalChange * Math.Sin( -this.angle ) - ( this.transformOrigin.Y * verticalChange * Math.Sin( -this.angle ) ) );
                        }
                        break;
                    case System.Windows.VerticalAlignment.Top:
                        if( scaleTransform.ScaleY != -1 )
                        {
                            Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + verticalChange * Math.Cos( -this.angle ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
                            Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) + verticalChange * Math.Sin( -this.angle ) - ( this.transformOrigin.Y * verticalChange * Math.Sin( -this.angle ) ) );
                        }
                        else
                        {
                            Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
                            Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) - verticalChange * this.transformOrigin.Y * Math.Sin( -this.angle ) );
                        }
                        break;
                    default:
                        break;
                }
                switch( HorizontalAlignment )
                {
                    case System.Windows.HorizontalAlignment.Left:
                        if( scaleTransform.ScaleX != -1 )
                        {
                            Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + horizontalChange * Math.Sin( this.angle ) - this.transformOrigin.X * horizontalChange * Math.Sin( this.angle ) );
                            Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) + horizontalChange * Math.Cos( this.angle ) + ( this.transformOrigin.X * horizontalChange * ( 1 - Math.Cos( this.angle ) ) ) );
                        }
                        else
                        {
                            Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) - this.transformOrigin.X * horizontalChange * Math.Sin( this.angle ) );
                            Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) + ( horizontalChange * this.transformOrigin.X * ( 1 - Math.Cos( this.angle ) ) ) );
                        }
                        break;
                    case System.Windows.HorizontalAlignment.Right:
                        if( scaleTransform.ScaleX != -1 )
                        {
                            Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) - this.transformOrigin.X * horizontalChange * Math.Sin( this.angle ) );
                            Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) + ( horizontalChange * this.transformOrigin.X * ( 1 - Math.Cos( this.angle ) ) ) );
                        }
                        else
                        {
                            Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + horizontalChange * Math.Sin( this.angle ) - this.transformOrigin.X * horizontalChange * Math.Sin( this.angle ) );
                            Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) + horizontalChange * Math.Cos( this.angle ) + ( this.transformOrigin.X * horizontalChange * ( 1 - Math.Cos( this.angle ) ) ) );
                        }
                        break;
                    default:
                        break;
                }                   
            }

            e.Handled = true;
        }

        private bool dragging_from_corner()
        {
            if( ( VerticalAlignment == VerticalAlignment.Top || VerticalAlignment == VerticalAlignment.Bottom ) &&
                ( HorizontalAlignment == HorizontalAlignment.Left || HorizontalAlignment == HorizontalAlignment.Right ) )
            {
                return true;
            }

            return false;
        }

        private void aspect_ratio_resizing( double originalHeight, double originalWidth, double newHeight, double newWidth )
        {
            double ratioWidth = newWidth / originalWidth;
            double ratioHeight = newHeight / originalHeight;
            double ratio = Math.Min( ratioWidth, ratioHeight );

            if( originalHeight * ratio > this.designerItem.MinHeight && originalWidth * ratio > this.designerItem.MinWidth )
            {
                this.designerItem.Height = originalHeight * ratio;
                this.designerItem.Width = originalWidth * ratio;
            }
        }
    }
}

这是我的RotateThumb代码:

namespace ResizeRotateFlip
{
    public class RotateThumb : Thumb
    {
        private Point centerPoint;
        private Vector startVector;
        private double initialAngle;
        private Canvas designerCanvas;
        private ContentControl designerItem;

        public RotateThumb()
        {
            DragDelta += new DragDeltaEventHandler( this.RotateThumb_DragDelta );
            DragStarted += new DragStartedEventHandler( this.RotateThumb_DragStarted );
        }

        private void RotateThumb_DragStarted( object sender, DragStartedEventArgs e )
        {
            this.designerItem = DataContext as ContentControl;

            if( this.designerItem != null )
            {
                this.designerCanvas = VisualTreeHelper.GetParent( this.designerItem ) as Canvas;

                if( this.designerCanvas != null )
                {
                    this.centerPoint = this.designerItem.TranslatePoint(
                        new Point( this.designerItem.Width * this.designerItem.RenderTransformOrigin.X,
                                  this.designerItem.Height * this.designerItem.RenderTransformOrigin.Y ),
                                  this.designerCanvas );

                    Point startPoint = Mouse.GetPosition( this.designerCanvas );
                    this.startVector = Point.Subtract( startPoint, this.centerPoint );

                    TransformGroup transformGroup = this.designerItem.RenderTransform as TransformGroup;
                    RotateTransform rotateTransform = transformGroup.Children[(int)TransformType.RotateTransform] as RotateTransform;

                    if( rotateTransform == null )
                    {
                        initialAngle = 0;
                    }
                    else
                    {
                        this.initialAngle = rotateTransform.Angle;
                    }
                }
            }
        }

        private void RotateThumb_DragDelta( object sender, DragDeltaEventArgs e )
        {
            if( this.designerItem != null && this.designerCanvas != null )
            {
                TransformGroup transformGroup = this.designerItem.RenderTransform as TransformGroup;
                ScaleTransform scaleTransform = transformGroup.Children[(int)TransformType.ScaleTransform] as ScaleTransform;

                double multiplier = scaleTransform.ScaleX * scaleTransform.ScaleY;

                Point currentPoint = Mouse.GetPosition( this.designerCanvas );
                Vector deltaVector = Point.Subtract( currentPoint, this.centerPoint );

                double angle = Vector.AngleBetween( this.startVector, deltaVector );

                RotateTransform rotateTransform = transformGroup.Children[(int)TransformType.RotateTransform] as RotateTransform;
                rotateTransform.Angle = this.initialAngle + ( Math.Round( angle, 0 ) ) * multiplier;

                this.designerItem.InvalidateMeasure();
            }
        }
    }
}

我猜测我对X和Y的计算变化(在ResizeThumb中)是不正确的。因此,在调整大小后,翻译未正确应用。虽然我注意到我对RotateThumb的更改对调整大小有影响,但在RotateThumb中使用TransformGroup之前,控件在旋转时会正确调整大小。

我引用的项目用途:

    case System.Windows.VerticalAlignment.Bottom:
        Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
        Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) - verticalChange * this.transformOrigin.Y * Math.Sin( -this.angle ) );
    break;

用于计算X&的新位置例如Y:但是我不知道如果翻转控件如何计算。 - 我应该注意到我在这里使用verticalChange而不是deltaVertical的原因是,当使用deltaHorizo​​ntal和deltaVertical时,控件往往会在画布上移动。

我想我的问题更多的是数学方面,我如何计算X&的新位置?是,当控件旋转并翻转时?

修改 我刚才注意到的一件事是在ResizeThumb的DragStarted方法中,我还没有访问过TransformGroup的RotateTransform。

我改变了:

RotateTransform rotateTransform = this.designerItem.RenderTransform as RotateTransform;

为:

TransformGroup transformGroup = designerItem.RenderTransform as TransformGroup;
RotateTransform rotateTransform = transformGroup.Children[(int)TransformType.RotateTransform] as RotateTransform;

这解决了当ScaleX和ScaleY没有被更改时调整大小错误的问题,但是当我翻转控件时,我仍然会调整大小问题。

1 个答案:

答案 0 :(得分:1)

我想我已经解决了!现在看起来很明显......

对于翻译,我这样做:

switch( VerticalAlignment )
                {
                    case System.Windows.VerticalAlignment.Bottom:
                        if( scaleTransform.ScaleY != -1 )
                        {
                            Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
                            Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) - verticalChange * this.transformOrigin.Y * Math.Sin( -this.angle ) );
                        }
                        else
                        {
                            Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + verticalChange * Math.Cos( -this.angle ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
                            Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) + verticalChange * Math.Sin( -this.angle ) - ( this.transformOrigin.Y * verticalChange * Math.Sin( -this.angle ) ) );
                        }
                        break;
                    case System.Windows.VerticalAlignment.Top:
                        if( scaleTransform.ScaleY != -1 )
                        {
                            Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + verticalChange * Math.Cos( -this.angle ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
                            Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) + verticalChange * Math.Sin( -this.angle ) - ( this.transformOrigin.Y * verticalChange * Math.Sin( -this.angle ) ) );
                        }
                        else
                        {
                            Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
                            Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) - verticalChange * this.transformOrigin.Y * Math.Sin( -this.angle ) );
                        }
                        break;
                    default:
                        break;
                }

当ScaleY设置为-1时,我只使用VerticalAlignment.Top中的VeticalAlignment.Bottom计算。反之亦然。但是对于Canvas.SetLeft来说这是没有意义的。

所以我把它改成了:

switch( VerticalAlignment )
                {
                    case System.Windows.VerticalAlignment.Bottom:
                        if( scaleTransform.ScaleY != -1 )
                        {
                            Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
                        }
                        else
                        {
                            Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + verticalChange * Math.Cos( -this.angle ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );

                        }
                        if( scaleTransform.ScaleX != -1 )
                        {
                            Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) - verticalChange * this.transformOrigin.Y * Math.Sin( -this.angle ) );
                        }
                        else
                        {
                            Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) + verticalChange * Math.Sin( -this.angle ) - ( this.transformOrigin.Y * verticalChange * Math.Sin( -this.angle ) ) );
                        }
                        break;
                    case System.Windows.VerticalAlignment.Top:
                        if( scaleTransform.ScaleY != -1 )
                        {
                            Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + verticalChange * Math.Cos( -this.angle ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
                        }
                        else
                        {
                            Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
                        }
                        if( scaleTransform.ScaleX != -1 )
                        {
                            Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) + verticalChange * Math.Sin( -this.angle ) - ( this.transformOrigin.Y * verticalChange * Math.Sin( -this.angle ) ) );
                        }
                        else
                        {
                            Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) - verticalChange * this.transformOrigin.Y * Math.Sin( -this.angle ) );
                        }
                        break;
                    default:
                        break;
                }

现在,SetTop和SetLeft会根据其比例进行适当设置。