WPF: Come applicare una GeneralTransform ai dati di una geometria e restituire la nuova geometria?

StackOverflow https://stackoverflow.com/questions/249971

Domanda

Avere alcuni dati Geometry e una Transform come si può applicare la Transform alla Geometry per ottenere una nuova Geometry con i suoi dati trasformati?

Esempio: ho un oggetto Path con Path.Data impostato su un oggetto PathGeometry, voglio trasformare i punti dell'oggetto PathGeometry in posizione usando un trasformare e non applicare una trasformazione a PathGeometry che verrà utilizzata al momento del rendering.

P.S. So che la classe Transform ha un metodo Point Transform.Transform (Point p) che può essere usato per trasformare un Point ma ... c'è un modo per trasformare una geometria arbitraria in una volta?

Modifica:   Vedi la mia risposta per un soluzione

È stato utile?

Soluzione

Puoi provare ad usare Geometry.Combine. Applica una trasformazione durante la mietitrebbia. Un problema è che Combine funziona solo se la tua Geometria ha un'area, quindi le singole linee non funzioneranno.

Ecco un esempio che ha funzionato per 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);

Altri suggerimenti

Ho trovato una soluzione con cui la trasformazione arbitraria può essere applicata a una geometria del percorso, grazie a La risposta di Todd White :

Fondamentalmente Geometry.Combine è usato per combinare la geometria desiderata con Geometry.Empty usando Union, e viene data la trasformazione desiderata. La geometria risultante viene trasformata con la trasformazione specificata.

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

Questo è quello che ho scoperto che puoi fare per ottenere una geometria trasformata con tutte le informazioni sulla figura intatte:

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

Non ho usato la risposta accettata poiché restituiva una geometria in un formato diverso da quello originale, quindi ho usato questo:

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

Nessuna delle soluzioni rapide basate su Geometry.Combine funziona nel caso di un percorso costituito da un singolo LineElement. Quindi ho risolto il problema nel modo più duro, in questo modo (ma sono anche limitato a 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;
}
}

Sfortunatamente, non penso che ci sia un metodo o una proprietà per fare ciò che stai chiedendo. Almeno, non riesco a trovarne uno. (Ottima domanda!)

Sembra che dovresti farlo manualmente (come suggerisci te stesso) ... cioè chiamare Point Transform.Transform (Point p) per ogni punto del PathGeometry ... creando un nuovo PathGeometry nel processo.

Probabilmente non è la risposta che vuoi. (Rueful Grin)

Ho avuto lo stesso problema E ho anche bisogno di linee (non solo geometrie con area).

Sto solo usando PathGeometry, quindi questa potrebbe non essere la soluzione generale che stai cercando, ma ha funzionato per me:

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

Ci sono due cose che devi considerare:

  1. La geometria eredita da Freezable, non è possibile modificare l'oggetto della geometria sul posto se è bloccato.
  2. Puoi scansionare l'elenco PathGeometry di figure e segmenti e trasformare tutti i punti in essi contenuti, ma alcuni tipi, come ArcSegment, include dimensioni e angoli, non puoi trasformarli.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top