WPF - UIElement.RenderSize not working for Line shape - wpf

I'm trying to make some drawing application and I get strange results in my "selection mode". If I draw a rectangle and "select it" RenderSize returns proper Size for it, but if Line is selected RenderSize returns Size which has Width set as Line.X2, and Height set as Line.Y2. For example: Line begins at X1 = 50, Y1 = 50, ends at X2 = 130, Y2 = 90, RenderSize returns Size with Width = 130 and Height = 90. My selection contains elements of type UIElement so I don't know (and really shouldn't care) what shape is selected in order to make my selection mode as generic as I can and I'd like to draw bounding box while user moves selected shape.
Tried google the problem but found nothing relevant so maybe you could help me with it. Is it because Rectangle has position set by Canvas while Line has its points set explicitly?

The reason you're getting 130x90 is because of the reason you cited. A Rectangle in WPF is position-less, it's just a height/width so the two size values are equal.
However a Line as defined by points necessarily defines a required offset from the origin, and thus the offset is included in the bounding box.
Also note that you can continue to use the Canvas.Top/Left properties with your Line object to further offset it, e.g.:
<Canvas>
<Line X1="50" X2="130" Y1="50" Y2="90" StrokeThickness="1" Stroke="Blue" Canvas.Top="50" Canvas.Left="30"></Line>
</Canvas>

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.

Increase StrokeThickness but maintain dimensions of Path

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.

How can I draw a circle sector with the ellipse class?

I would like to make a sector of a circle on WP7. I tried to do this with the ellipse class and I found a lot of solution, which make a gauge or pie chart or something, but I need just the essence.
Could anyone help?
the aim is to show just one part of a circle (or ellipse). Like the yellow area in the picture:
Thanks,
Laci
Here's a fairly simple solution to the problem, though it does not use an Ellipse and it requires a little trigonometry:
<Path Fill="Black"
Data="M0,0 L0,-100 A100,100 0 0 1 70.7,-70.7 z" />
The Data property uses Path Markup Syntax.
The "M" at the beginning tells the pen to Move to the location 0,0.
The "L" tells the pen to draw a Line from the current location (0, 0) to 0,-100.
The "A" tells the pen to draw an elliptical Arc from the current location to 70.7,-70.7 (the "100,100" portion determines the horizontal and vertical radius of the ellipse and the "0 0 1" portion is for RotationAngle, IsLargeArc, and SweepDirection (1 for clockwise, 0 for counter-clockwise)).
The "z" tells the pen to close or complete the shape (which will cause a line to be drawn from 70.7,-70.7 back to 0,0).
Where did the 70.7 come from? Well, this particular arc sweeps out an angle of 45 degrees from a circle with radius 100, so the coordinates 70.7,-70.7 are determined by 100 * sin(45) and 100 * cos(45).
You need to do something like this:
define a canvas wrapper for ellipse
define the visible part of the canvas (clip). For this part you need to use PathGeometry as the Clip to define the slice of the circle you want to be visible. (see link)
<Canvas>
<Canvas.Clip>
<PathGeometry>
// define your path here (see link above)
</PathGeometry>
<Ellipse Background="Yellow" Width="200" Height="200" />
</Canvas.Clip>
</Canvas>
Alternatively you can use CombinedGeometry to combine a PathGeometry and EllipseGeometry to form the slice. (the link provides a good example of CombinedGeometry)

How to make some layer mask in Silverlight?

I have an image object and a rectangle object. Now I want to be the image to be only visible where the rectangle is, everything else should have an opacity of 0.5 - the result should look something simliar to the following:
When I set the opacity of the rectangle to 0.5 the effect is the antipode - so how could I realize it as shown in the image? Size and position of the rectangle is changed by code-behind, but that shouldn't make any differences...
All hints / answeres appreciated :)
If you want to add an opaque mask to partially hide your image outside of a rectangle, it's rather easy.
<Grid>
<Image Source="myImage.jpg" Opacity="0.5/>
<Image Source="myImage.jpg" >
<Image.Clip>
<RectangleGeometry Rect="x,y,w,h"/>
</Image.Clip>
</Image>
</Grid>
Where x,y,w and h are your rectangle position and size (see MSDN). If you want to move the visible portion around, set the Clip property by code.
If you want to add the "black stroke effect", you could simply add a Rectangle with position and size matching those of your clipping path after the second image in your grid.
Do you want more infos?

Resources