Лучшим решением было бы использовать один или несколько объектов System.Windows.Media.Geometry для хранения ваших путей, точек и т. Д.
Эту геометрию можно нарисовать пером, поэтому вы действительно можете изменять толщину обводки при масштабировании, но более гибким является использование свойства Transform.
Используя преобразование, вы можете «масштабировать» фактические координаты геометрического представления, а не визуализацию - поэтому при рисовании вам не нужно возиться с преобразованиями рендеринга.
Для вычисления преобразования я использую следующий код:
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;
}
, где объект fromPosition Rect должен содержать нетрансформированные границы, а объект toPosition Rect должен содержать преобразованные границы. Это также тривиально позволяет масштабировать X и Y отдельно, что часто необходимо для построения графика.
Легко вычислить границы вашей геометрии:
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);
И, конечно же, WPF может сказать вам, в какие границы вам нужно визуализировать, если это будет необходимо. Собрав все вместе, вы могли бы сделать что-то вроде
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);
}
Преимущество использования этого решения в том, что вам не нужно связываться с RenderTransforms, вы можете свободно использовать преобразования, которые срезают и / или масштабируют X и Y, не получая странных искажений в ваших строках, и вы можете лечить Перо как непрозрачный объект (т. е. его проще настраивать из пользовательского интерфейса - если вы выберете ширину пера или что-то еще, дальнейшая коррекция не требуется).