Подтвердить что ты не робот

WPF: как применить данные GeneralTransform к геометрии и вернуть новую геометрию?

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

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

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

Изменить: См. Мой вариант для найденного в настоящее время решения

4b9b3361

Ответ 1

Вы можете попробовать использовать Geometry.Combine. Он применяет преобразование во время комбайна. Один улов заключается в том, что 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);

Ответ 2

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

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

PathGeometry geometryTransformed = Geometry.Combine(Geometry.Empty, geometry, GeometryCombineMode.Union, 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.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;
}
}

Ответ 5

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

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

Ответ 6

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

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

Возможно, это не тот ответ, который вы хотите. (Rueful Grin)

Ответ 7

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

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

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

Ответ 8

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

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