WPF: Как применить GeneralTransform к данным Geometry и вернуть новую геометрию? - PullRequest
12 голосов
/ 30 октября 2008

Имея некоторые данные геометрии и преобразование, как преобразование можно применить к геометрии, чтобы получить новую геометрию с преобразованными данными?

Пример: у меня есть объект Path, для которого Path. Data установлен как объект PathGeometry, я хочу преобразовать точки объекта PathGeometry вместо , используя преобразование, и не применять преобразование к PathGeometry, которое будет использоваться во время рендеринга.

P.S. Я знаю, что в классе Transform есть метод Point Transform.Transform(Point p), который можно использовать для преобразования точки, но ... есть ли способ преобразовать произвольную геометрию одновременно?

Edit: Смотрите мой репплей для найденного на данный момент решения

Ответы [ 8 ]

11 голосов
/ 30 октября 2008

Я нашел решение, с помощью которого произвольный преобразование можно применить к геометрии пути, благодаря ответу Тодда Уайта :

В основном Geometry.Combine используется для объединения нужной геометрии с Geometry.Empty с помощью Union, и заданный желаемый преобразователь дается. Результирующая геометрия преобразуется с помощью данного преобразования.

PathGeometry geometryTransformed = Geometry.Combine(Geometry.Empty, geometry, GeometryCombineMode.Union, transform);
9 голосов
/ 30 октября 2008

Вы можете попробовать использовать 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);
6 голосов
/ 19 декабря 2012

Это то, что я нашел, вы можете сделать, чтобы получить преобразованную геометрию со всей информацией о фигуре без изменений:

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); 
3 голосов
/ 22 сентября 2011

Я не использовал принятый ответ, так как он возвращал геометрию в формате, отличном от исходного, поэтому я использовал это:

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();
2 голосов
/ 16 декабря 2014

Ни одно из быстрых решений, основанных на 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;
}
}
0 голосов
/ 01 октября 2009

У меня была такая же проблема И нужны линии (не только геометрия с площадью).

Я использую только PathGeometry, так что, возможно, это не общее решение, которое вы ищете, но это сработало для меня:

pathgeometry.Transform = transform;
PathGeometry transformed =  PathGeometry.CreateFromGeometry(pathgeometry);
0 голосов
/ 30 октября 2008

К сожалению, я не думаю, что есть метод или свойство, чтобы сделать то, что вы просите. По крайней мере, я не могу найти один. (Отличный вопрос!)

Кажется, что вам придется делать это вручную (как вы сами себе) ... то есть вызов Point Transform.Transform (Point p) для каждой точки вашей PathGeometry ... создание новая PathGeometry в процессе.

Возможно, это не тот ответ, который вам нужен. (грустная улыбка)

0 голосов
/ 30 октября 2008

Есть две вещи, которые вы должны учитывать:

  1. Геометрия наследуется от Freezable, вы не можете изменить геометрический объект на месте, если он заморожен.
  2. Вы можете отсканировать список фигур и сегментов PathGeometry и преобразовать все точки в них, но некоторые типы, например ArcSegment, включают размеры и углы, вы не можете их преобразовать.
...