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

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

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

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

Редактировать: См. Мой ответ о найденном на данный момент решение

Если вы действительно найдете способ сделать это ... Я тоже им воспользуюсь. Хе-хе.

cplotts 30.10.2008 17:18
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
13
1
13 765
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Вы должны учитывать две вещи:

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

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

Pop Catalin 30.10.2008 15:52

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

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

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

Не уверен, почему это было отклонено, поскольку это кажется единственно правильным ответом.

Goran 23.10.2010 03:31
Ответ принят как подходящий

Вы можете попробовать использовать Geometry.Combine. Он применяет преобразование во время комбинирования. Одна загвоздка заключается в том, что Combine работает только в том случае, если ваша Geometry имеет площадь, поэтому отдельные линии не будут работать.

Вот образец, который у меня сработал.

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

Единственная проблема в том, что комбинированная геометрия не совпадает с исходной геометрией. Различия невелики, но могут быть важны.

Goran 23.10.2010 03:28

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

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

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

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

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

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

Вы действительно получаете преобразованную геометрию? Применение CreateFromGeometry к PathGeometry возвращает ту же геометрию (те же точки). Вы не трансформируете геометрию, а просто добавляете свойство трансформации.

Goran 23.10.2010 03:30

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

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

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

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

Кажется, это правильный способ сделать это, поскольку СтандартРазверстиеТолерантность не применяется.

ManIkWeet 15.02.2019 11:53

Ни одно из быстрых решений на основе 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;
}
}

Другие вопросы по теме