6

シェイプに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をスケーリングし、0.25でxをスケールするように変換をプッシュすることは問題なく機能しましたが、結果の形状描画は適用されなかったようです。 Stretch = fill、私はこれに依存しています)。したがって、レンダリング変換で欠けているものがあるはずです。

動作していないテストシナリオは次のとおりです。

  • xamlでscaleX=4およびscaleY=1のレンダリングスケール変換を適用します。
  • 組み込みのPathクラスは、y方向よりもx方向のストロークが4倍になるように、図面全体を拡大縮小します。
  • MyPathで、ストロークではなく、ジオメトリのみをスケーリングする必要があります。<-これは機能していません!
    • 何が起こるか:ジオメトリは正しくスケーリングされ、ストロークはx方向に4だけスケーリングされ、y方向に4よりわずかに小さくなります。なにが問題ですか?RenderedGeometry.Transformだけで作業するべきではないと感じていますが、代わりに何を使用すればよいですか?シェイプにレンダートランスフォームとstretch=fillを組み込む必要があります。私のレンダートランスフォーム階層には、スケール、回転、平行移動が混在している可能性があるため、ソリューションは、軸に沿ったスケーリングだけでなく、あらゆるトランスフォームを処理するのに十分一般的である必要があります。

注:OnRenderでジオ​​メトリを作成するのは悪いことですが、クリーンアップに時間を費やす前に、ジオメトリを機能させたいと思っています。

ちなみに、私はこの投稿を読みました:

スケールに関係なく、パスのストロークの太さは不変です

前に述べた問題は、レンダリング変換を考慮に入れる必要があり、それらを使用するためにそのソリューションをどのように適応させるかがわからないことです。

4

1 に答える 1

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();
于 2012-11-13T06:00:22.007 に答える