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

发布于 2024-07-08 07:36:12 字数 498 浏览 10 评论 0原文

有了一些几何数据和变换,如何将变换应用于几何以获得数据变换后的新几何?

例如:我有一个 Path 对象,其 Path.Data 设置为 PathGeometry 对象,我想使用变换就地变换 PathGeometry 对象的,并且不对渲染时使用的 PathGeometry 应用变换。

PS 我知道 Transform 类有一个方法 Point Transform.Transform(Point p) ,可用于变换 Point 但是......有没有办法立即变换任意几何图形?

编辑: 请参阅我的回复,了解当前找到的 解决方案

Having some Geometry data and a Transform how can the transform be applied to the Geometry to get a new Geometry with it's data transformed ?

Ex: I Have a Path object that has it's Path.Data set to a PathGeometry object, I want to tranform the points of the PathGeometry object in place using a transform, and not apply a transform to the PathGeometry that will be used at render time.

P.S. I know that the Transform class has a method Point Transform.Transform(Point p) that can be used to transform a Point but...is there a way to transform a arbitrary geometry at once?

Edit:
See my repply for a currently found solution

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

梦过后 2024-07-15 07:36:13

我找到了一种可以将任意变换应用于路径几何图形的解决方案,这要归功于 Todd White 的回答:

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

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

I've found a solution with which arbitrary tranform can be applied to a path geometry, thanks to Todd White's answer:

Basically Geometry.Combine is used to combine the desired geometry with Geometry.Empty using Union, and the desired transform is given. The resulting geometry is transformed with the given transform.

PathGeometry geometryTransformed = Geometry.Combine(Geometry.Empty, geometry, GeometryCombineMode.Union, transform);
握住我的手 2024-07-15 07:36:13

您可以尝试使用 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);

You could try and use Geometry.Combine. It applies a transform during the combine. One catch is that Combine only works if your Geometry has area, so single lines will not work.

Here is a sample that worked for me.

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);
花开柳相依 2024-07-15 07:36:13

我发现您可以这样做来获得所有图形信息完好无损的转换后的几何图形:

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

This is what I found you can do to get a transformed geometry with all of the figure information intact:

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); 
じ违心 2024-07-15 07:36:13

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

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

I didn't use accepted answer since it was returning geometry in format different from the original one, so I used this:

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();
单挑你×的.吻 2024-07-15 07:36:13

对于由单个 LineElement 构成的路径,基于 Geometry.Combine 的快速解决方案都不起作用。
所以我用困难的方式解决了这个问题,就像这样(但我也仅限于 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;
}
}

None of the quick solutions based on Geometry.Combine works in the case of path made of a single LineElement.
So I solved the problem the hard way, like this (But I am also limited to 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;
}
}
谎言 2024-07-15 07:36:13

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

看来您必须手动执行此操作(正如您自己建议的那样)...即为 PathGeometry 中的每个点调用 Point Transform.Transform(Point p) ..在此过程中创建一个新的 PathGeometry。

可能不是你想要的答案。 (悔恨的笑容)

Unfortunately, I don't think there is a method or property to do what you are asking. At least, I can't find one. (Great question!)

It seems like you would have to do it manually (as you suggest yourself) ... that is call Point Transform.Transform(Point p) for every point in your PathGeometry ... creating a new PathGeometry in the process.

Probably isn't the answer you want. (Rueful Grin)

红衣飘飘貌似仙 2024-07-15 07:36:13

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

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

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

I've had the same problem AND need lines as well (not only geometries with area).

I'm only using PathGeometry, so this may not be the general solution you are looking for, but this worked for me:

pathgeometry.Transform = transform;
PathGeometry transformed =  PathGeometry.CreateFromGeometry(pathgeometry);
瘫痪情歌 2024-07-15 07:36:13

您必须考虑两件事:

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

There are two things you have to consider:

  1. Geometry inherits from Freezable, you can't modify the geometry object in-place if it's frozen.
  2. You can scan the PathGeometry list of figures and segments and transform all the points in them but some types, like ArcSegment includes sizes and angles, you can't transform them.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文