C# WPF:如何将 GeneralTransform 应用于几何数据并返回新几何?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/249971/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 19:55:30  来源:igfitidea点击:

WPF: How to apply a GeneralTransform to a Geometry data and return the new geometry?

c#.netwpfgeometrytransform

提问by Pop Catalin

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 pointsof the PathGeometry object in placeusing a transform, and not apply a transform to the PathGeometry that will be used at render time.

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

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?

PS 我知道 Transform 类有一个方法Point Transform.Transform(Point p)可以用来转换一个点,但是......有没有办法一次转换任意几何?

Edit: See my repply for a currently found solution

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

采纳答案by Todd White

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.

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

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

回答by Nir

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.
  1. 几何体继承自 Freezable,如果几何体对象被冻结,则无法就地修改几何体对象。
  2. 您可以扫描图形和线段的 PathGeometry 列表并转换其中的所有点,但某些类型,如 ArcSegment 包括大小和角度,您无法转换它们。

回答by cplotts

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.

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

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

可能不是你想要的答案。(遗憾的笑容)

回答by Pop Catalin

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

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

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.

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

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

回答by Pop Catalin

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,所以这可能不是您正在寻找的通用解决方案,但这对我有用:

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

回答by Snowbear

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

回答by Curtis

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

回答by rpaulin56

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

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