WPF:如何将GeneralTransform应用于几何体数据并返回新的几何体

本文关键字:几何体 数据 返回 应用于 GeneralTransform WPF | 更新日期: 2023-09-27 17:47:46

拥有一些几何体数据和一个变换如何将变换应用于几何体以获得一个新的几何体?

例如:我有一个Path对象,它有自己的Path。数据集为PathGeometry对象,我想使用变换将Path几何对象的点变换到适当的位置,而不是将变换应用于渲染时使用的PathGeometry。

附言:我知道Transform类有一个方法Point Transform.Transform(Point p),可以用来转换点,但。。。有没有一种方法可以同时变换任意几何体?

编辑:请参阅我的repply以获取当前找到的解决方案

WPF:如何将GeneralTransform应用于几何体数据并返回新的几何体

由于Todd White的回答,我找到了一个可以将任意变换应用于路径几何的解决方案:

基本上是几何体。Combine用于将所需的几何体与几何体组合。使用并集清空,并给出所需的变换。生成的几何体将使用给定的变换进行变换。

PathGeometry geometryTransformed = Geometry.Combine(Geometry.Empty, geometry, GeometryCombineMode.Union, transform);

您可以尝试使用Geometry.Combine。它在组合过程中应用变换。一个问题是,只有当几何体有面积时,"组合"才有效,所以单条线不起作用。

这是一个对我有用的样品。

PathGeometry geometry = new PathGeometry();
geometry.Figures.Add(new PathFigure(new Point(10, 10), new PathSegment[] { new LineSegment(new Point(10, 20), true), new LineSegment(new Point(20, 20), true) }, true));
ScaleTransform transform = new ScaleTransform(2, 2);
PathGeometry geometryTransformed = Geometry.Combine(geometry, geometry, GeometryCombineMode.Intersect, transform);

这就是我发现你可以做的,在所有图形信息不变的情况下获得变换后的几何体:

var geometry = new PathGeometry();
geometry.Figures.Add(new PathFigure(new Point(10, 10), new PathSegment[] { new LineSegment(new Point(10, 20), true), new LineSegment(new Point(20, 20), true) }, true));
geometry.Transform = new ScaleTransform(2, 2);
var transformedGeometry = new PathGeometry ();
// this copies the transformed figures one by one into the new geometry
transformedGeometry.AddGeometry (geometry); 

我没有使用已接受的答案,因为它以不同于原始格式的格式返回几何体,所以我使用了这个:

Geometry inputGeometry = new PathGeometry();
var inputGeometryClone = inputGeometry.Clone(); // we need a clone since in order to
                                                // apply a Transform and geometry might be readonly
inputGeometryClone.Transform = new TranslateTransform(); // applying some transform to it
var result = inputGeometryClone.GetFlattenedPathGeometry();

没有一个基于Geometry.Combine的快速解决方案适用于由单个LineElement组成的路径。所以我用艰难的方式解决了这个问题,就像这样(但我也局限于PathGeometry):

public static class GeometryHelper
{
public static PointCollection TransformPoints(PointCollection pc, Transform t)
{
  PointCollection tp = new PointCollection(pc.Count);
  foreach (Point p in pc)
    tp.Add(t.Transform(p));
  return tp;
}
public static PathGeometry TransformedGeometry(PathGeometry g, Transform t)
{
  Matrix m = t.Value;
  double scaleX = Math.Sqrt(m.M11 * m.M11 + m.M21 * m.M21);
  double scaleY = (m.M11 * m.M22 - m.M12 * m.M21) / scaleX;
  PathGeometry ng = g.Clone();
  foreach (PathFigure f in ng.Figures)
  {
    f.StartPoint = t.Transform(f.StartPoint);
    foreach (PathSegment s in f.Segments)
    {
      if (s is LineSegment)
        (s as LineSegment).Point = t.Transform((s as LineSegment).Point);
      else if (s is PolyLineSegment)
        (s as PolyLineSegment).Points = TransformPoints((s as PolyLineSegment).Points, t);
      else if (s is BezierSegment)
      {
        (s as BezierSegment).Point1 = t.Transform((s as BezierSegment).Point1);
        (s as BezierSegment).Point2 = t.Transform((s as BezierSegment).Point2);
        (s as BezierSegment).Point3 = t.Transform((s as BezierSegment).Point3);
      }
      else if (s is PolyBezierSegment)
        (s as PolyBezierSegment).Points = TransformPoints((s as PolyBezierSegment).Points, t);
      else if (s is QuadraticBezierSegment)
      {
        (s as QuadraticBezierSegment).Point1 = t.Transform((s as QuadraticBezierSegment).Point1);
        (s as QuadraticBezierSegment).Point2 = t.Transform((s as QuadraticBezierSegment).Point2);
      }
      else if (s is PolyQuadraticBezierSegment)
        (s as PolyQuadraticBezierSegment).Points = TransformPoints((s as PolyQuadraticBezierSegment).Points, t);
      else if (s is ArcSegment)
      {
        ArcSegment a = s as ArcSegment;
        a.Point = t.Transform(a.Point);
        a.Size = new Size(a.Size.Width * scaleX, a.Size.Height * scaleY); // NEVER TRIED
      }
    }
  }
  return ng;
}
}

不幸的是,我不认为有一个方法或属性可以满足您的要求。至少,我找不到。(好问题!)

看起来你必须手动完成(就像你自己建议的那样)。。。即调用点变换。对PathGeometry中的每个点进行变换(点p)。。。在此过程中创建新的PathGeometry。

可能不是你想要的答案(Rueuful Grin)

我也遇到过同样的问题,也需要线条(不仅仅是有面积的几何图形)。

我只使用PathGeometry,所以这可能不是你想要的通用解决方案,但这对我很有效:

pathgeometry.Transform = transform;
PathGeometry transformed =  PathGeometry.CreateFromGeometry(pathgeometry);

您必须考虑两件事:

  1. 几何体继承自Freezable,如果几何体对象被冻结,则不能在原地修改它
  2. 您可以扫描地物和线段的PathGeometry列表并变换其中的所有点,但某些类型(如ArcSegment)包括大小和角度,您无法变换它们