WPF形状几何缩放而不影响笔划

时间:2012-11-06 22:42:42

标签: wpf

我想知道是否有人在将scaletransform应用于形状时设法覆盖了WPF形状渲染的默认行为。默认行为会转换整个形状图形,包括笔划,但我只想缩放几何体。困难在于我的形状存在于视觉层次结构中,渲染变换应用于不同的层次(有点像2D场景图,但是WPF可视化树),我无法改变(!)。我已经在不同的地方读过,可以创建一个自定义形状来取消渲染变换的变换并将其放在几何体上。目前我有类似的东西:

public sealed class MyPath : Shape
{
    // This class has a Data property of type Geometry just like the normal Path class

    protected override Geometry DefiningGeometry
    {
        get
        {
            Geometry data = Data;

            if (data == null)
            {
                data = Geometry.Empty;
            }

            return data;
        }
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        Transform tr = RenderedGeometry.Transform;
        Geometry geomToDraw = RenderedGeometry.Clone();
        geomToDraw.Transform = new MatrixTransform(tr.Value * tr.Value);
        Matrix trInv = tr.Value; trInv.Invert();
        drawingContext.PushTransform(new MatrixTransform(trInv));
        drawingContext.DrawGeometry(Brushes.Transparent, new Pen() { Brush = Brushes.Black, Thickness = 1 }, geomToDraw);
    }
}

很明显,我对此很新,上面的代码可能完全搞砸了。我试图将矩阵转移到几何体而不改变最终得到的几何变换,因此tr.Value * tr.Value和trInv。但它并不像我想要的那样有效。我知道这种传递变换技术在理论上是有效的,因为我用恒定变换进行了尝试(测试设置Geometry.Transform以使用4缩放x并将变换推进到缩​​放x,使用0.25工作正常,但得到的形状图似乎不适用stretch = fill,我依赖)。因此渲染转换必须存在一些我遗漏的东西。

无效的测试场景是:

  • 我在xaml中应用了scaleX = 4和scaleY = 1的渲染比例变换。
  • 内置的Path类缩放整个绘图,使x方向的笔划比y方向宽4倍。
  • 我希望MyPath只缩放几何体,而不是笔划。 < - 这不工作!
    • 发生的事情是:几何体正确缩放,笔划在x方向上缩放4,在y方向稍微缩小4。怎么了?我有一种感觉,我不应该只使用RenderedGeometry.Transform,但我应该使用什么呢?我需要在形状上加入渲染变换和stretch = fill。我的渲染变换层次结构可能包含缩放,旋转和平移的混合,因此解决方案必须足够通用以处理任何变换,而不仅仅是轴对齐缩放。

注意:我知道在OnRender中创建几何体是不好的,但是我想在花时间清理它之前让它工作。

顺便说一下,我读了这篇文章:

Invariant stroke thickness of Path regardless of the scale

前面提到的问题是我必须考虑渲染变换,我不确定如何调整该解决方案以使用它们。

1 个答案:

答案 0 :(得分:3)

如果我正确理解了这个问题,你想要取消渲染变换对笔的影响,而不是几何体。

这可以通过相对于你想要取消变换的项目获得控件的变换来实现,使用其反转来抵消对笔的影响。 (例如,如果您有层次结构P1 / P2 / P3 / UrShape,并且P1,P2,P3都对它们进行了变换,并且您希望所有这些都不会影响您的笔,则需要获得P1相对的变换到UrShape)。然后你可以将变换重新应用到你的形状。

var brush = new SolidColorBrush(Colors.Red);
var pen = new Pen(brush, 5);
//Instead of the direct parent you could walk up the visual tree to the root from where you want to cancel the transform

var rootTransform = (MatrixTransform)this.TransformToAncestor((Visual)this.Parent);

var inverserRootTransform = (MatrixTransform)rootTransform.Inverse;

//We cancel out the transformation from the parent 
drawingContext.PushTransform(inverserRootTransform);

var renderGeometry = this.Geometry.Clone();
// We apply the parent transform to the shape only, and group it with the original transform that was present on the shape
// we do this to honor any transformation that was set on the shape.
renderGeometry.Transform = new TransformGroup()
{
   Children =
   {
      rootTransform,
      this.Geometry.Transform
   }
};

//We draw the shape, the pen size will have the correct size since we canceled out the transform from the parent
// but the shape now has the transformation directly on it.
drawingContext.DrawGeometry(brush, pen, renderGeometry);
drawingContext.Pop();