tags:

views:

707

answers:

2

Hello!

We are using wpf to develop a cad like application where drawings placed on the canvas using the Path object. I just ran into a slight issue that whenver i scale/zoom my canvas, all the elements in the canvas get scaled and this is the behaviour i wanted but this also increases the stroke thickness of the Path.

Is there a way by which i increase/scale/zoom the objects but still i maintain the same stroke thickness of the path.

Any help in this regard will be very useful for me.

+1  A: 

Hello !

Finally i got the workaround for the above solution what i have done is i m setting the strokethickness of the path relative to the scaling i m doing on canvas.

like this

path.strokeness = 1/(scaling factor applied to the canvas)

This is fine if your x and y scales are uniform, but does not work if the scales are not the same.
Klay
+3  A: 

A better solution would be to use one or more System.Windows.Media.Geometry object to store your paths, points etc.

This geometry can be drawn with a Pen, so you could indeed change the stroke thickness when you zoom, but more flexible is to use the Transform property.

Using the transform, you can "zoom" the actual coordinates of the geometric representation and not the visualization - so when you draw it, you don't need to fiddle with render transforms.

To compute the transform, I use the following code like:

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

where the fromPosition Rect should contain the untransformed bounds, and the toPosition Rect should contain the transformed bounds. This also trivially allows for scaling X and Y separately, which is often necessary for plotting.

It's easy to compute the bounds of your geometry:

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

And of course WPF can tell you which bounds you need to render into, should that be necessary. Putting it together, you could do something like

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

The advantage of using this solution is that you don't need to mess with RenderTransforms, you're free to use transforms that shear and/or scale X and Y independently without getting weird distortions in your lines, and you can treat the Pen as an opaque object (i.e. easier to customize from the UI - if you select Pen width or whatnot, no further correction is necessary).

Eamon Nerbonne