转换WPF GeometryDrawing,有效地更改GeometryDrawing路径指向的位置 [英] Transform WPF GeometryDrawing where the GeometryDrawing path points are effectively changed

查看:179
本文介绍了转换WPF GeometryDrawing,有效地更改GeometryDrawing路径指向的位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何缩放有效更改GeometryDrawing路径指向的WPF GeometryDrawing?我想要做的是我有一个GeometryDrawings的DrawingGroup,我想调整其中一个GeometryDrawings。



我知道我可以将这个Geometrydrawing放在一个单独的DrawingGroup中,并使用ScaleTransform来缩放这个GeometryDrawing但是:



1.我无法设置特定的宽度和高度我必须使用比例因子,因此它将紧密地指定我指定的宽度但不完全是我指定的宽度;

2. GeometryDrawing不会改变,但缩放就像一个效果,我想使ScaleTransform(和其他变换)有效,真的改变GeometryDrawing的路径点。



有我试图改变自己的路径,但结果并不是我的预期。调整大小并且路径已损坏时,路径将被翻译。



祝你好运,


$ b $bRémy



How do I scale a WPF GeometryDrawing where the GeometryDrawing path points are effectively changed? What I want to do is that I have a DrawingGroup of GeometryDrawings and I want to resize one of these GeometryDrawings.

I know I can put this Geometrydrawing in a separate DrawingGroup and use ScaleTransform to scale this GeometryDrawing but:

1. I can’t set specific widths and heights I have to use a scale factor, so it will closely be the width I specify but not exactly the width I specify;
2. The GeometryDrawing doesn’t change but is zoomed like an effect, I would like to make the ScaleTransform (and other transforms) effective, really change the pathpoints of the GeometryDrawing.

Have tried to change the pathpoints myself but the endresult is not what I expected. The path is translated when resized and the path is corrupted.

Best regards,

Rémy

private void SetScaleAndTranslateTransform(object obj, Point newPos, Size newSize)
{
    double translateX = 0;
    double translateY = 0;
    double scaleWidth = 1;
    double scaleHeight = 1;

    if (obj is System.Windows.Media.GeometryDrawing)
    {
        System.Windows.Media.GeometryDrawing geometryDrawing = (System.Windows.Media.GeometryDrawing)obj;
        translateX = newPos.X - geometryDrawing.Bounds.X;
        translateY = newPos.Y - geometryDrawing.Bounds.Y;
        scaleWidth = newSize.Width / geometryDrawing.Bounds.Width;
        scaleHeight = newSize.Height / geometryDrawing.Bounds.Height;
    }
    else if (obj is System.Windows.Media.DrawingGroup)
    {
        System.Windows.Media.DrawingGroup drawingGroup = (System.Windows.Media.DrawingGroup)obj;
        translateX = newPos.X - drawingGroup.Bounds.X;
        translateY = newPos.Y - drawingGroup.Bounds.Y;
        scaleWidth = newSize.Width / drawingGroup.Bounds.Width;
        scaleHeight = newSize.Height / drawingGroup.Bounds.Height;
    }

    SetScaleAndTranslateTransform(obj, translateX, translateY, scaleWidth, scaleHeight);

    CreateSelectionImage(null);
}

private void SetScaleAndTranslateTransform(object obj, double translateX, double translateY, double scaleWidth, double scaleHeight)
{
    if (obj is System.Windows.Media.GeometryDrawing)
    {
        System.Windows.Media.GeometryDrawing geometryDrawing = (System.Windows.Media.GeometryDrawing)obj;

        Geometry geoMetry = geometryDrawing.Geometry;
        PathGeometry pathGeometry = (PathGeometry)geoMetry;
        foreach (PathFigure pathFigure in pathGeometry.Figures)
        {
            pathFigure.StartPoint = new Point(pathFigure.StartPoint.X + translateX, pathFigure.StartPoint.Y - translateY);
            foreach(PathSegment pathSegment in pathFigure.Segments)
            {
                PointCollection pointCollectionOriginal = new PointCollection();
                if (pathSegment is PolyBezierSegment)
                {
                    pointCollectionOriginal = ((PolyBezierSegment)pathSegment).Points;
                }
                else if (pathSegment is LineSegment)
                {
                    pointCollectionOriginal.Add(((LineSegment)pathSegment).Point);
                }
                else if (pathSegment is PolyLineSegment)
                {
                    pointCollectionOriginal = ((PolyLineSegment)pathSegment).Points;
                }

                PointCollection pointCollectionNew = new PointCollection();
                foreach (Point point in pointCollectionOriginal)
                {
                    Point pointNew = new Point();
                    pointNew.X = point.X * scaleWidth;
                    pointNew.Y = point.Y * scaleHeight;
                    pointCollectionNew.Add(pointNew);
                }

                if (pathSegment is PolyBezierSegment)
                {
                    ((PolyBezierSegment)pathSegment).Points = pointCollectionNew;
                }
                else if (pathSegment is LineSegment)
                {
                    ((LineSegment)pathSegment).Point = pointCollectionNew[0];
                }
                else if (pathSegment is PolyLineSegment)
                {
                    ((PolyLineSegment)pathSegment).Points = pointCollectionNew;
                }
            }
        }
    }
    else if (obj is System.Windows.Media.DrawingGroup)
    {
        System.Windows.Media.DrawingGroup drawingGroup = (System.Windows.Media.DrawingGroup)obj;
        foreach(object objChild in drawingGroup.Children)
        {
            SetScaleAndTranslateTransform(objChild, translateX, translateY, scaleWidth, scaleHeight);
        }
    }
}





Dan的巨大帮助,因为这是我在代码中使用的代码:





With HUGE help from DanBecause this is the code I use in my code:

public static void TransformPoints(this PathFigure figure, Transform t)
{
    figure.StartPoint = t.Transform(figure.StartPoint);

    foreach (var segment in figure.Segments)
    {
        if (segment is LineSegment)
        {
            var lineSegment = segment as LineSegment;
            Point newPoint = t.Transform(lineSegment.Point);
            lineSegment.Point = newPoint;
        }
        else if (segment is PolyLineSegment)
        {
            var polyLineSegment = segment as PolyLineSegment;
            PointCollection pointCollection = new PointCollection();
            foreach (var point in polyLineSegment.Points)
            {
                pointCollection.Add(t.Transform(point));
            }
            polyLineSegment.Points = pointCollection;
        }
        else if (segment is PolyBezierSegment)
        {
            var polyBezierSegment = segment as PolyBezierSegment;
            PointCollection pointCollection = new PointCollection();
            foreach (var point in polyBezierSegment.Points)
            {
                pointCollection.Add(t.Transform(point));
            }
            polyBezierSegment.Points = pointCollection;
        }
        else
        {
            throw new Exception(segment.GetType().ToString());
        }
    }
}

private void SetScaleAndTranslateTransform(object obj, Point newPos, Size newSize)
{
    double translateX = 0;
    double translateY = 0;
    double scaleWidth = 1;
    double scaleHeight = 1;

    if (obj is System.Windows.Media.GeometryDrawing)
    {
        System.Windows.Media.GeometryDrawing geometryDrawing = (System.Windows.Media.GeometryDrawing)obj;
        translateX = newPos.X - geometryDrawing.Bounds.X;
        translateY = newPos.Y - geometryDrawing.Bounds.Y;
        scaleWidth = newSize.Width / geometryDrawing.Bounds.Width;
        scaleHeight = newSize.Height / geometryDrawing.Bounds.Height;
    }
    else if (obj is System.Windows.Media.DrawingGroup)
    {
        System.Windows.Media.DrawingGroup drawingGroup = (System.Windows.Media.DrawingGroup)obj;
        translateX = newPos.X - drawingGroup.Bounds.X;
        translateY = newPos.Y - drawingGroup.Bounds.Y;
        scaleWidth = newSize.Width / drawingGroup.Bounds.Width;
        scaleHeight = newSize.Height / drawingGroup.Bounds.Height;
    }

    SetScaleAndTranslateTransform(obj, translateX, translateY, scaleWidth, scaleHeight);
}

private void SetScaleAndTranslateTransform(object obj, double translateX, double translateY, double scaleWidth, double scaleHeight)
{
    if (obj is System.Windows.Media.GeometryDrawing)
    {
        System.Windows.Media.GeometryDrawing geometryDrawing = (System.Windows.Media.GeometryDrawing)obj;

        Geometry geoMetry = geometryDrawing.Geometry;
        PathGeometry pathGeometry = (PathGeometry)geoMetry;
        foreach (PathFigure pathFigure in pathGeometry.Figures)
        {
            Business.PathFigureExtensions.TransformPoints(pathFigure, new ScaleTransform(scaleWidth, scaleHeight));
            Business.PathFigureExtensions.TransformPoints(pathFigure, new TranslateTransform(translateX, translateY));
        }
    }
    else if (obj is System.Windows.Media.DrawingGroup)
    {
        System.Windows.Media.DrawingGroup drawingGroup = (System.Windows.Media.DrawingGroup)obj;
        foreach (object objChild in drawingGroup.Children)
        {
            SetScaleAndTranslateTransform(objChild, translateX, translateY, scaleWidth, scaleHeight);
        }
    }
}

推荐答案

我不能完全说我通过真正改变路径点来理解你的意思,但是几何上的Transform属性将在渲染之前缩放几何体,并且渲染几何体就好像它是缩放尺寸(不是原始尺寸的缩放版本) 。因此,例如,笔的厚度不会像使用视觉变换那样增加(或减少)。我想这就是你要找的。



所以也许:

I can't say I entirely understand what you mean by "really change the pathpoints", but the Transform property on the Geometry will scale the Geometry before it is rendered and the Geometry will be rendered as though it were the scaled size (not a zoomed version of the original size). So, for example, the pen thickness will not increase (or decrease) like it would with a visual transform. I think this is what you are looking for.

So perhaps:
private void SetScaleAndTranslateTransform(object obj, double translateX, double translateY, double scaleWidth, double scaleHeight)
{
    var geometryDrawing = obj as System.Windows.Media.GeometryDrawing;
    if(geometryDrawing != null)
    {
        geometryDrawing.Transform = new MatrixTransform(scaleWidth, 0, 0, scaleHeight, translateX, translate);
        return;
    }

    var drawingGroup = obj as System.Windows.Media.DrawingGroup;
    if(drawingGroup == null) return;

    foreach(object objChild in drawingGroup.Children)
        SetScaleAndTranslateTransform(objChild, translateX, translateY, scaleWidth, scaleHeight);
}





请记住,您也可以创建一次转换并将其分配给相应的几何实例然后只需修改该转换将影响所有这些转换而不必使用递归。



更新:

以下是快速示例说明了我说改变积分时的意思。





Keep in mind you could also create the transform once and assign it to the appropriate Geometry instances and then simply modifying that transform will affect all of them without having to use recursion.

Updated:
Below is a quick example illustrating what I mean when I say to transform the points.

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 WpfApplication3
{
	public static class PathFigureExtensions
	{
		public static IEnumerable<Point> EnumeratePoints(this PathFigure figure)
		{
			yield return figure.StartPoint;
			foreach (var segment in figure.Segments)
			{
				var lineSegment = segment as LineSegment;
				if (lineSegment != null)
					yield return lineSegment.Point;
				else
				{
					var polyLineSegment = segment as PolyLineSegment;
					if (polyLineSegment == null) continue;
					foreach (var point in polyLineSegment.Points)
						yield return point;
				}
			}
		}

		public static IEnumerable<Point> EnumeratePoints(this PathFigure figure, Transform t)
		{
            //Here I am transforming the points using the geometry's transform.
			return EnumeratePoints(figure).Select(p => t.Transform(p));
		}
	}

	/// <summary>
	/// Interaction logic for MainWindow.xaml
	/// </summary>
	public partial class MainWindow : Window
	{
		public MainWindow()
		{
			InitializeComponent();

			var figures = new[]{
				new PathFigure(
				new Point(0,0),
				new[]{
					new PolyLineSegment(
						new []{
							new Point(50,0),
							new Point(50,50),
							new Point(0,50),
						}, true) as PathSegment
				}, true)
			};

			UntransformedGeometry = new PathGeometry(figures);
			UntransformedGeometryPoints = new PointCollection(UntransformedGeometry.Figures.First().EnumeratePoints());

			TransformedGeometry = new PathGeometry(figures);
			TransformedGeometry.Transform = new ScaleTransform(2, 2);
			TransformedGeometryPoints = new PointCollection(UntransformedGeometry.Figures.First().EnumeratePoints(TransformedGeometry.Transform));
			DataContext = this;
		}

		public PathGeometry UntransformedGeometry {get;private set;}
		public PathGeometry TransformedGeometry { get; private set; }
		public PointCollection UntransformedGeometryPoints { get; private set; }
		public PointCollection TransformedGeometryPoints { get; private set; }

	}
}





这是我用来演示的xaml:



Here's the xaml I will use to demonstrate:

<Window x:Class="WpfApplication3.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="MainWindow" Height="350" Width="525">
    <StackPanel Margin="5">
        <Path Data="{Binding UntransformedGeometry}" Stroke="Red" Fill="Gray" StrokeThickness="1" UseLayoutRounding="true"/>
        <Label Content="{Binding UntransformedGeometryPoints}"/>
        <Path Data="{Binding TransformedGeometry}" Stroke="Blue" Fill="Gray" StrokeThickness="1" UseLayoutRounding="true"/>
        <Label Content="{Binding TransformedGeometryPoints}"/>
    </StackPanel>
</Window>





如果你运行这个,你会看到一个方形,上面有你给出的尺寸,一个带有分数的标签,另一个方块是原始方块的两倍,另一个标签显示转换的点。第二个方块具有与原始方块相同的明显笔划厚度,因为它在逻辑上是转换而不是在视觉上。



我还演示了PathGeometry如何不拥有这些数字用于创建它(我使用相同的PathFigure来创建两个geoetries);这只是将变换应用于PathFigure或Geometry等的多种原因之一,不应更改基础值。我认为这也是开发人员期望属性表现的方式;我可以看到有一个方法给定一个变换产生了一个新的Geometry,它具有应用变换得到的点(并且变换应用于它)。如果你愿意,你可以用你的GeometryDrawing几何图形交换(使其有效)。



这是一个快速而肮脏的例子。我可以看到你扩展各种PathSegment类型和PathFigure以在每个上公开这个功能,最后对PathGeometry这样做。



If you run this you will see a square with the dimensions you gave, a label with its points, another square twice as large as the original square, and another label showing the points transformed. The second square has the same apparent stroke thickness as the original square because it is logically transformed rather than visually.

I also demonstrate how the PathGeometry doesn't own the figures used to create it (I use the same PathFigure to create both geoetries); this is just one of many reasons why applying a transform to a PathFigure, or Geometry, etc. should not change the underlying values. I think this is also how a developer expect properties to behave; I could see having a method that given a transform produced a new Geometry that had the points resulting from applying the transform (and the transform not applied to it). You could exchange your GeometryDrawing's Geometry with that if you like (making it "effective").

This was a quick and dirty example. I could see you extending the various PathSegment types and PathFigure to expose this functionality on each and finally doing so to PathGeometry.


这篇关于转换WPF GeometryDrawing,有效地更改GeometryDrawing路径指向的位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆