Scale WPF shape geometry without affecting stroke

I am wondering if someone managed to override the default WPF rendering behavior when applying the scaletransform form to the form. The default behavior converts the entire figure of the figure, including strokes, but I would only like to scale the geometry. The difficulty is that my figures are in a visual hierarchy with visual transformations applied at different levels (like a 2D scene graphic, but a WPF visual tree), I cannot change this (!). I read in various places that it is possible to create a custom shape to undo the transformation to transform the visualization and put it in the geometry. At the moment, I have something like:

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); } } 

As you can clearly see, I'm completely new to this, and the code above is probably completely messed up. I tried to transfer the matrix into geometry without changing the final geometry transformation, so tr.Value * tr.Value and trInv. But it does not work as I want. I know that this transfer conversion technology works in theory because I tried it with constant conversions (testing to set Geometry.Transform to scale x from 4 and clicking on the conversion to x scale from 0.25 worked fine, but the resulting form drawing , it seems stretch = fill was not applied, which I will describe). So there must be something that I am missing with visual transformations.

A testing scenario that does not work is as follows:

  • I am applying scaled rendering conversion with scaleX = 4 and scaleY = 1 in xaml.
  • The built-in Path class scales the entire drawing so that the strokes are 4 times wider in the x direction than in the y direction.
  • I want MyPath to scale only geometry, not strokes. <- THIS DOES NOT WORK!
    • What happens: the geometry scales correctly, the strokes scale by 4 in the x direction and slightly less than 4 in the y direction. What's wrong? I have the feeling that I should not work only with RenderedGeometry.Transform, but what should I use instead? I need to enable rendering and stretch = fill out the form. My rendering transform hierarchy may contain a combination of scales, rotations, and translations, so the solution should be general enough to handle any transform, not just axis scaling.

Note. I know that creating geometry in OnRender is bad, but I want it to work before I spend time cleaning it.

By the way, I read this post:

Invariant stroke stroke thickness regardless of scale

The problem that was mentioned above is that I have to accept visualization transformations, and I'm not sure how to adapt this solution to work with them.

+6
source share
1 answer

If I understand the question correctly, you want to cancel the rendering effect on the handle, but not on the geometry.

You can do this by getting the control transform relative to the element from which you want to cancel the transform, using the inverse of it to cancel the effect on the handle. (for example, if you have a P1 / P2 / P3 / UrShape hierarchy, and P1, P2, P3 all have conversions on them, and you want them all not to affect your pen, you need to get a relative P1 to UrShape transformation) . Then you can reapply the conversion only to your form.

 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(); 
+3
source

All Articles