Сложность объединения ScaleTransform (WPF) с Transalate Transform во время рендеринга изображения

WPF.

(Я заранее извиняюсь за кажущуюся стенку кода, но проблема мне кажется сложной, и я хотел быть настолько полным, насколько это необходимо).

У меня есть изображение, которое сбрасывается на InkCanvas:

Перед изменением размера показывает:

Изменение контура траектории во время DragDelts показывает:

После DragCompleted. Примечание: Я ХОЧУ, ЧТОБЫ ЛУЧШИЙ УГЛОВОЙ УГОЛ был В ПОЛОЖЕНИИ "Х", ГДЕ КУРСОР НА ВРЕМЯ ДРАГКОМПЛЕТА:

Вот код, который я использую для получения изображений выше. По сути, проблема сводится к вычислению правильного преобразования преобразования после изменения размера изображения. Я перепробовал все, что могу придумать, но безуспешно. Что действительно вызывает недоумение, так это то, что смещение от курсора в некоторой степени зависит от положения, в которое изображение помещается в InkCanvas. То есть, если изображение сброшено ближе к левой границе, смещение будет более выраженным, чем если бы оно было опущено в центре. Очень запутанно.

private void IC_Drop(object sender, DragEventArgs e)
    {
        InkCanvas ic = sender as InkCanvas;

        ic.EditingMode = InkCanvasEditingMode.None;

        ImageInfo image_Info = e.Data.GetData(typeof(ImageInfo)) as ImageInfo;
        if (image_Info != null)
        { 
            Image image = new Image();
            image.Width = image_Info.Width * 4;
            image.Stretch = Stretch.Fill;           
            image.Source = new BitmapImage(image_Info.Uri);

            Point position = e.GetPosition(ic);
            TranslateTransform mov = new TranslateTransform(position.X, position.Y);
            image.RenderTransform = mov;
            ic.Children.Add(image);
            ImageResizing imgResize = ImageResizing.Create(image);
        }
    }

ImageResizing.Create () теперь добавляет rendertransforms и thumb thumbner к изображению для изменения размера, перемещения и поворота:

private ImageResizing(Image image)
    {
        if (image == null)
            throw new ArgumentNullException("image");

       _image = image;

        ScaleTransform scale = new ScaleTransform();
        RotateTransform rot = new RotateTransform();
        TranslateTransform mov = new TranslateTransform();

        TransformGroup tg = new TransformGroup();
        tg.Children.Add(image.RenderTransform);  
        tg.Children.Add(scale);                  
        tg.Children.Add(rot);                    
        tg.Children.Add(mov);                     
        image.RenderTransform = tg; 
        image.RenderTransformOrigin = new Point(0.5,0.5);

        // Create the adorner.
        _adorner = new MyImageAdorner(image);

        // Get the Adorner Layer and add the Adorner.
        InstallAdorner();
 }

Украшение TopLeft Thumb определяется с помощью:

  Thumb topLeft;
  Path outline;

  public MyImageAdorner(UIElement adornedElement)
      : base(adornedElement)
    {
        visualChildren = new VisualCollection(this);

        // Initialize the Resizing (i.e., corner) thumbs with specialized cursors.
        BuildAdornerCorner(ref topLeft, Cursors.SizeNWSE);
        topLeft.DragDelta += new DragDeltaEventHandler(TopLeft_DragDelta);
        topLeft.DragCompleted += TopLeft_DragCompleted;
    }

   // Helper method to instantiate the corner Thumbs, set the Cursor property, 
    // set some appearance properties, and add the elements to the visual tree.
    void BuildAdornerCorner(ref Thumb cornerThumb, Cursor customizedCursor)
    {
        if (cornerThumb != null) return;

        cornerThumb = new Thumb();

        // Set some arbitrary visual characteristics.
        cornerThumb.Cursor = customizedCursor;
        cornerThumb.Height = cornerThumb.Width = 15;
        cornerThumb.Opacity = 0.40;
        cornerThumb.Background = new SolidColorBrush(Colors.MediumBlue);

        visualChildren.Add(cornerThumb);
    }

Я использую DragDelta для позиционирования элемента контура контура до желаемого конечного размера, например, так:

 // Top Left Corner is being dragged. Anchor is Bottom Right.

    void TopLeft_DragDelta(object sender, DragDeltaEventArgs e)
    {
        ScaleTransform sT = new ScaleTransform(1 - e.HorizontalChange / outline.ActualWidth, 1 - e.VerticalChange / outline.ActualHeight,
            outline.ActualWidth, outline.ActualHeight);

        outline.RenderTransform = sT;   
    }

Обратите внимание, что я собираюсь изменить размер изображения в верхнем правом углу в нижнем правом углу. Следовательно, по мере перетаскивания угла TopLeft все точки изображения должны удаляться от нижнего правого угла.

Наконец, я использую событие DragCompleted для фактического выполнения нового рендеринга на изображении:

  private void TopLeft_DragCompleted(object sender, DragCompletedEventArgs e)
    {
        // Get new scaling from the Outline.
        ScaleTransform sT = outline.RenderTransform as ScaleTransform;
        double anchorX = sT.CenterX;
        double anchorY = sT.CenterY;

        // Get the previous scaling
        TransformGroup gT = AdornedElement.RenderTransform as TransformGroup;
        ScaleTransform sT0 = gT.Children[1] as ScaleTransform;
        double oldscaleX = sT0.ScaleX;
        double oldscaleY = sT0.ScaleY;

        double oldCenterX = anchorX - (outline.ActualWidth ) * oldscaleX;
        double oldCenterY = anchorY - (outline.ActualHeight) * oldscaleY;

        // Get the previous translation
        TranslateTransform tT = gT.Children[3] as TranslateTransform;

        sT0.CenterX = anchorX;
        sT0.CenterY = anchorY;

        sT0.ScaleX *= sT.ScaleX;
        sT0.ScaleY *= sT.ScaleY;

        double newCenterX = anchorX -(outline.ActualWidth) * sT0.ScaleX;
        double newCenterY = anchorY -(outline.ActualHeight) * sT0.ScaleY;

        tT.X += newCenterX - oldCenterX;
        tT.Y += newCenterY - oldCenterY;

        // Put transforms back.
        gT.Children[1] = sT0;
        gT.Children[3] = tT;

        AdornedElement.RenderTransform = gT;
        outline.RenderTransform = Transform.Identity;  

    }

А для полноты, рекламодатель позиционируется как:

  protected override Size ArrangeOverride(Size finalSize)
    {
        double eW = AdornedElement.RenderSize.Width;
        double eH = AdornedElement.RenderSize.Height;
        FrameworkElement ele = AdornedElement as FrameworkElement;
        EnforceSize(ele);
        eH = ele.Height;
        eW = ele.Width;

        Size aS = new Size(eW, eH);

        // calculate the center of the image.
        var center = new Point(eW / 2, eH / 2);

        topLeft.Arrange(new Rect(new Point(-center.X, -center.Y), aS));
        topRight.Arrange(new Rect(new Point(center.X, -center.Y), aS));
        bottomLeft.Arrange(new Rect(new Point(-center.X, center.Y), aS));
        bottomRight.Arrange(new Rect(new Point(center.X, center.Y), aS));

        // The RotateHandle is placed slightly above the Top of the Image center.
        // The MoveHandle is placed at the center of the Image.
        rotateHandle.Arrange(new Rect(new Point(0, -(center.Y + HANDLEMARGIN)), aS));
        moveHandle.Arrange(new Rect(new Point(0, 0), aS));

        // Place a blue outline arround the image.
        outline.Data = new RectangleGeometry(new Rect(aS));
        outline.Arrange(new Rect(aS));

        // Return the final size.
        return aS;
    }

Я был бы признателен за любую помощь или предложения. Что я делаю неправильно?

ТИА

Примечание. На этот вопрос дан ответ. Масштабирование, вызывающее перекос

0 ответов

Другие вопросы по тегам