WPF:如何将GeneralTransform应用于Geometry数据并返回新的几何?
题
有一些几何数据和一个变换如何将变换应用于几何体以获得一个新的几何体,并将其转换成数据?
Ex:我有一个Path对象,它的Path.Data设置为PathGeometry对象,我想使用一个转换 PathGeometry对象的 到位变换,而不是将变换应用于将在渲染时使用的PathGeometry。
P.S。我知道Transform类有一个方法 Point Transform.Transform(Point p)
,它可以用来转换Point但是......有没有办法一次转换任意几何?
编辑: 查看当前找到的溶液
解决方案
您可以尝试使用Geometry.Combine。它在组合期间应用变换。一个问题是,只有在你的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);
其他提示
我找到了一个解决方案,可以将任意转换应用于路径几何,这要归功于 Todd White 的回答:
基本上Geometry.Combine用于使用Union将所需几何与Geometry.Empty组合,并给出所需的变换。使用给定的变换转换生成的几何。
PathGeometry geometryTransformed = Geometry.Combine(Geometry.Empty, geometry, GeometryCombineMode.Union, 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中的每个点,都要调用 Point Transform.Transform(Point p) ...创建这个过程中新的PathGeometry。
可能不是你想要的答案。 (Rueful Grin)
我遇到了同样的问题并且也需要线条(不仅是带有面积的几何图形)。
我只使用PathGeometry,所以这可能不是您正在寻找的一般解决方案,但这对我有用:
pathgeometry.Transform = transform;
PathGeometry transformed = PathGeometry.CreateFromGeometry(pathgeometry);
您必须考虑两件事:
- Geometry继承自Freezable,如果它被冻结,则无法就地修改几何对象。
- 您可以扫描图形和线段的PathGeometry列表并转换其中的所有点,但某些类型(如ArcSegment包含大小和角度),您无法对其进行转换。 醇>