Инвариантная толщина хода пути независимо от масштаба - PullRequest
22 голосов
/ 07 апреля 2009

Мы используем wpf для разработки приложения, похожего на cad, в котором рисунки размещаются на холсте с использованием объекта Path. Я столкнулся с небольшой проблемой: когда я масштабирую / масштабирую свой холст, все элементы на холсте масштабируются, и это поведение, которое я хотел, но это также увеличивает толщину обводки пути.

Есть ли способ, с помощью которого я увеличиваю / масштабирую / увеличиваю объекты, но при этом сохраняю одинаковую толщину обводки пути.

Любая помощь в этом отношении будет очень полезна для меня.

Ответы [ 3 ]

13 голосов
/ 21 апреля 2009

Лучшим решением было бы использовать один или несколько объектов 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, не получая странных искажений в ваших строках, и вы можете лечить Перо как непрозрачный объект (т. е. его проще настраивать из пользовательского интерфейса - если вы выберете ширину пера или что-то еще, дальнейшая коррекция не требуется).

7 голосов
/ 08 апреля 2009

Наконец-то я нашел обходной путь для вышеуказанного решения. Я сделал это, установив StrokeThickness Path относительно масштабирования Canvas.

Как это:

// scale = scaling factor applied to the canvas
path.StrokeThickness = 1.0 / scale;

Это работает, только если ScaleX и ScaleY одинаковы.

0 голосов
/ 28 апреля 2017

Я был здесь несколько раз, но мне пришла в голову эта идея, как насчет того, чтобы просто обернуть ее в Viewbox?

Вы можете попробовать это: использование высоты / ширины не должно изменять соотношение толщины к размеру. Может быть, это делает другие плохие вещи, которые я еще не обнаружил ...

<Viewbox Height="50" Width="50">
    <Path Stroke="Black" Fill="Black" StrokeThickness="0.8" Stretch="Uniform" 
                 Data="M0,0 20,20" />
</Viewbox>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...