Una mejor solución sería utilizar uno o más objetos System.Windows.Media.Geometry para almacenar sus caminos, puntos, etc.
Esta geometría se puede dibujar con una pluma, por lo que de hecho podría cambiar el trazo grosor al hacer zoom, pero más flexible es usar la propiedad Transformar.
Utilizando la transformación, puede "acercar" las coordenadas reales de la representación geométrica y no la visualización, de modo que cuando la dibuje, no tenga que manipular las transformaciones de representación.
Para calcular la transformada, utilizo el siguiente código como:
public static Matrix TransformShape(Rect fromPosition, Rect toPosition, bool flipVertical) {
Matrix translateThenScale = Matrix.Identity;
//we first translate to origin since that's just easier
translateThenScale.Translate(-fromPosition.X, -fromPosition.Y);
//now we scale the graph to the appropriate dimensions
translateThenScale.Scale(toPosition.Width/fromPosition.Width, toPosition.Height/fromPosition.Height);
//then we flip the graph vertically around the viewport middle since in our graph positive is up, not down.
if (flipVertical)
translateThenScale.ScaleAt(1.0, -1.0, 0.0, toPosition.Height/2.0);
//now we push the graph to the right spot, which will usually simply be 0,0.
translateThenScale.Translate(toPosition.X, toPosition.Y);
return translateThenScale;
}
donde el fromPosition Rect debe contener los límites no transformadas, y la toPosition Rect debe contener los límites transformadas. Esto también permite trivialmente escalar X e Y por separado, lo que a menudo es necesario para trazar.
Es fácil de calcular los límites de la geometría:
Geometry graphGeom;
//[...]
//the bounds are modified by the transform, so we want no transform!
graphGeom.Transform = Transform.Identity;
Rect graphBounds = graphGeom.Bounds;
//then set the transform again
//or, if the transform is axis-aligned, the following _should_ work:
Rect graphBoundsAlt = graphGeom.Transform.Inverse.TransformBounds(graphGeom.Bounds);
Y, por supuesto WPF se puede decir que limita lo que necesita para hacer entrar, si ello fuera necesario. Juntando todo, usted podría hacer algo como
public void RecomputeTransform(Rect targetRect, bool flipVertical) {
graphGeom.Transform = Transform.Identity;
Rect graphBounds = graphGeom.Bounds;
Matrix transMat = TransformShape(graphBounds,targetRect,flipVertical);
graphGeom.Transform = new MatrixTransform(transMat);
}
La ventaja de utilizar esta solución es que no es necesario meterse con RenderTransforms, usted es libre de utilizar transformaciones que X cizalla y/o la escala e Y de forma independiente sin obtener distorsiones extrañas en sus líneas, y puede tratar el Pen como un objeto opaco (es decir, más fácil de personalizar desde la UI; si selecciona el ancho del Pen o lo que sea, no es necesario realizar más correcciones).
Esto está bien si sus escalas xey son uniformes, pero no funciona si las escalas no son las mismas. – Klay