Increase StrokeThickness but maintain dimensions of Path - wpf

I have a Path that normally has a StrokeThickness of 1. Under certain circumstances, it needs to have a StrokeThickness of 10. When I increase the stroke thickness, I don't want the path to take any additional space.
By default, just increasing the StrokeThickness increases the rendered size of the path. So you get something like this (the blue outline extends beyond the black boundary):
This is what I'm trying to achieve (the blue outline stays within the black boundary):
I can think of two mathematical ways to compensate for the increased StrokeWidth:
Manually adjust the points of the triangle inward.
Use a ScaleTransform on the Geometry of the Path.
Both of these would be somewhat problematic/complex. Is there an easier way?

You could clip the path by its own geometry like this:
<Path ... Clip="{Binding Data, RelativeSource={RelativeSource Self}}"/>
but then you would need to double the StrokeThickness, since only half of the stroke is visible.

On a whim I set StrokeThickness = -1 on my Rectangle and it did exactly what I wanted it to: the stroke goes on the inside of the Rectangle rather than on the outside.

Related

Stroke alignment in Cairo

Many graphics packages allow the user to select where they would like to draw the border of a region around a shape; either along the inside, outside or centre of the shape. For example, this shows the same square with the border drawn along the centre, inside and outside respectively:
I could scale the path up/down based on the stroke's width, but I wanted to check if there was built-in support for this first.
I'm using Ruby, but if there's a C method for this, it's likely available in the Ruby bindings as well.
Is there a method to draw a stroke around the outside or inside of a path, rather than along the centre, in Cairo?
No, there is no such method built-in.
One could likely approximate this with a temporary surface that is later used as a mask. For example, to do "outside", you first fill a temporary surface with "transparent", then stroke with twice your desired line width some "opaque", and finally fill the shape with "transparent" to get rid of the inner part of the line width. The resulting surface can then be used as a mask.
"Inside" would be similar, but with an extra trick: Again, transparent surface and stroke with twice the line width. Now the outside part of this stroke needs to be removed. For this, one needs a path with a winding rule of even-odd. Add a surface-sized rectangle to this path inverts the path, thus allowing to remove everything outside via a fill.
For a non-zero winding rule... I do not have any immediate ideas (well, another temporary surface that is then inverted via a full-surface-paint with operator SUBTRACT?).
Sample code for drawing outside of the path (see comments):
static void draw_outside_of_path(cairo_t *cr) {
double line_width = cairo_get_line_width(cr);
cairo_pattern_t *mask;
cairo_push_group_with_content(cr, CAIRO_CONTENT_ALPHA);
cairo_set_line_width(cr, 2 * line_width);
cairo_set_source_rgba(cr, 0, 0, 0, 1);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_stroke_preserve(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_fill_preserve(cr);
mask = cairo_pop_group(cr);
cairo_mask(cr, mask);
cairo_pattern_destroy(mask);
}
For stroking inside a path, set the path as a clipping region, then stroke the path; any part of stroke that lies outside the clipping region will be unseen...

Understanding Stroke and StrokeThickness in relation to Height

Below I have a rectangle:
<Rectangle ClipToBounds="False" Grid.Row="1"
StrokeThickness="6"
StrokeDashArray=".5"
Height="2"
Stroke="Green" />
In the definition above, I have observed that to see the effect of StrokeDashArray=".5", I have to maintain the StrokeThickness between 6 to 9. If I give anything below 6 or above 9, I see a straight line.
I have two questions here:
In the above example, StrokeDashArray effect does not work below 6 and above 9. Why?
I think there is a relation between height and StrokeThickness. Can someone please explain?
When I read the MSDN Definition on stroke thickness it says:
Gets or sets the width of the Shape outline
I do not understand this.
Thanks in advance.
The stroke dash array is not expressed in pixels, it's dependent upon stroke thickness to get the final pixel value for each number in the array.
look here if you want to understand all the details behind it.
Generally speaking: The StrokeThickness tells WPF how thick
the line should be in pixels.
StrokeDashArray is a property that allows us to define the dashes and gaps in a
line. The values in the array alternate between the length of the dash and the
length of the gap. The values are also relative to the thickness of the stroke, so a
value of 1.0 means that the length of the corresponding dash or gap is equal to the
width of the stroke.
In your code you tell WPF to draw a dash that is 0.5 times of the width of the stroke but you didn't give the length of the gap, for example:
StrokeDashArray=".5 1"
This example says that the gap is equal to 1 time of the width.
Buttom line you need to define the gap for getting the wanted gap between the dashes.

Label CornerRadius

I have a dockpanel which contains an array of Label (Rectangles) inherited from Border class, which contains CornerRadius property. So, everything is good, but when I start resizing the window, or add the labels to the dockpanel, their size narrows and the Corner remains the same as it was with the bigger label size!! For example, I have a big size label 300*300 with CornerRadius 30. It looks good, but when I resize the window (make it much smaller) it turns into circle.
I tried to implement the special coefficient but nothing helps. Maybe i have made mistake.
Border is "keeping" it's corner radius regardless of it's actual size. And that's usually a good thing.
In your case, I'd use a Path (NOTE: not a Rectangle).
Using Expression Blend, you can draw a Rectangle of a certain size, set it's RadiusX and RadiusY properties and then make a path out of it (there's an option in the menus, under 'Tools', IIRC). The path will scale (and warp) it's corner radius.
Having said that, what do you need this functionality for? Maybe ViewBox will do the job without inheritance?

Can't see stroke

I derive from shape, this is what is in the DefiningGeometry
protected override Geometry DefiningGeometry
{
get
{
topLeft.X = Math.Min(Start.X, End.X);
topLeft.Y = Math.Min(Start.Y, End.Y);
width.X = Math.Abs(Start.X - End.X);
width.Y = Math.Abs(Start.Y - End.Y);
rectBounds.X = topLeft.X;
rectBounds.Y = topLeft.Y;
rectBounds.Width = width.X;
rectBounds.Height = width.Y;
rectGeo.Rect = rectBounds;
return rectGeo;
}
}
I see the fill, but not the stroke, since the sroke is additional to the width and height I tried to make some room for it by setting:
Width = width.X + StrokeThickness;
//same for height.
But then nothing gets drawn, does anyone know what I am doing wrong? By the way the background and the stroke brush are different color.
Stroke is always on top of Fill. Thicknesses below 1.0 are no problem at all, although very thin strokes naturally tend to become invisible.
Fill exactly fills the Shape's geometry. Stroke renders the geometry's outline, half of the stroke lying inside, half outside the shape.
Never add StrokeThickness to your Shape's width (which would only work as you expect on rectangles anyway). See the MSDN for how the Shape's properties behave.
Do not derive from Shape to create simple geometric objects. Use the predefined Rectangle, Ellipse, Line etc. Use Path for more complex geometries and set Path.Data.
Also consult the Shapes and Basic Drawing in WPF Overview and maybe the Geometry Overview in the MSDN.
StrokeThickness for some reason should be larger than 1 (I am guessing the Fill brush is covering it), or don't set the Fill property, and StrokeThickness 1 works.

Does RenderTransformOrigin influence scale transforms?

I am trying to do scale transforms on an InkCanvas and some unseen force seems to be influencing how the scale works. When I try to set CenterX and CenterY they appear to be being ignored.
Update: I should note that the ink canvas is wrapped with a viewbox, I suppose that could be influencing it too...
I tried it out and it does. E.g. in order to make a control sweep from right to left I moved the RenderTransformOrigin to "1, 0" .
I am not certain about the documentation but it could be that CenterX/Y relate not to normalized proportions but to the actual size of the UIElement. If that's the case it is sort of useless.

Resources