Ответ 1
Лучшим решением было бы использовать один или несколько объектов System.Windows.Media.Geometry для хранения ваших путей, точек и т.д.
Эта геометрия может быть нарисована с помощью Pen, поэтому вы можете действительно изменить толщину штриха при масштабировании, но более гибким является использование свойства Transform.
Используя преобразование, вы можете "масштабировать" фактические координаты геометрического представления, а не визуализацию, поэтому, когда вы его рисуете, вам не нужно возиться с визуальными преобразованиями.
Чтобы вычислить преобразование, я использую следующий код:
public static Matrix TransformShape(Rect fromPosition, Rect toPosition, bool flipVertical) {
Matrix translateThenScale = Matrix.Identity;
//we first translate to origin since that 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 независимо, не получая странных искажений в ваших линиях, и вы можете лечить Перо в качестве непрозрачного объекта (т.е. проще настроить из пользовательского интерфейса - если вы выберете ширину пера или еще что-то еще, дальнейшая коррекция не нужна).