【问题标题】:WPF: How to apply a GeneralTransform to a Geometry data and return the new geometry?WPF:如何将 GeneralTransform 应用于几何数据并返回新几何?
【发布时间】:2010-09-19 23:34:20
【问题描述】:

拥有一些几何数据和一个变换,如何将变换应用于几何以得到一个新的几何,其数据已转换?

例如:我有一个 Path 对象,它的 Path.Data 设置为 PathGeometry 对象,我想使用变换,而不是对将在渲染时使用的 PathGeometry 应用变换。

附:我知道 Transform 类有一个方法 Point Transform.Transform(Point p) 可以用来变换一个 Point 但是......有没有办法一次变换任意几何体?

编辑: 查看我对当前找到的solution的回复

【问题讨论】:

  • 如果你真的找到了一种方法来做到这一点......我也在使用它。嘿嘿。

标签: c# .net wpf geometry transform


【解决方案1】:

基于 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;
}
}

【讨论】:

    【解决方案2】:

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

    我只使用 PathGeometry,所以这可能不是您正在寻找的通用解决方案,但这对我有用:

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

    【讨论】:

    • 你真的得到了转换后的几何图形吗?在 PathGeometry 上应用 CreateFromGeometry 返回相同的几何图形(相同的点)。您不是在转换几何,而只是添加了 transform 属性。
    【解决方案3】:

    我发现你可以这样做来获得一个完整的所有图形信息的转换几何:

    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); 
    

    【讨论】:

    【解决方案4】:

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

    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();
    

    【讨论】:

      【解决方案5】:

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

      基本上 Geometry.Combine 用于将所需的几何图形与 Geometry.Empty 使用 Union 进行组合,并给出所需的变换。生成的几何图形使用给定的变换进行变换。

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

      【讨论】:

        【解决方案6】:

        您可以尝试使用 Geometry.Combine。它在合并期间应用变换。一个问题是,Combine 仅在您的 Geometry 具有区域时才有效,因此单行将不起作用。

        这是一个对我有用的示例。

        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);
        

        【讨论】:

        • 唯一的问题是组合几何与原始几何不同。差异不大,但可能很重要。
        【解决方案7】:

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

        似乎您必须手动进行(正如您自己建议的那样)...即为 PathGeometry 中的每个点调用 Point Transform.Transform(Point p) ...创建一个新的 PathGeometry 正在处理中。

        可能不是您想要的答案。 (悲伤的笑容)

        【讨论】:

        • 不知道为什么这被否决了,因为它似乎是唯一正确的答案。
        【解决方案8】:

        您必须考虑两件事:

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

        【讨论】:

        • 你可以变换任何东西,甚至是大小和角度,此外,我知道你可以单独变换点,而且我的几何体也没有被冻结。我想知道是否有一种框架方法可以将转换应用于整个几何对象。
        猜你喜欢
        • 1970-01-01
        • 2012-05-25
        • 1970-01-01
        • 1970-01-01
        • 2021-10-03
        • 1970-01-01
        • 2021-12-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多