Programmatically split a path into multiple paths - wpf

I have a dynamically generated path whose data is composed of a PathGeometry composed of a PathFigure. This PathFigure contains a bunch of line segments. So the overall path is continuous, composed of straight lines. What is a good approach to split this path into many many different little paths? If you are curious, the reason I need to do this is to achieve a 'path fading away' effect, and there doesn't seem to be another way to do this.
So I want to take a path, and split it into many different little paths, and then I will set the opacity of the first little path to 0, and the last little path to 1, and interpolate for everything in between. Also, I could use this to make the tail of the path small, and interpolate up to the head of the path, which is big. There are many uses - I need a way to do this for my application.

See GradientPath by Charles Petzold it is implemented similar to how you describe and should be easy to tweak if you want to add support for altering the width of the path.

Rather than splitting up the path, it sounds like you may be able to simply use a linear gradient brush for the stroke color of the path to accomplish the same effect of your path fading. For example, try setting the brush below on your path.
In Xaml:
<Path.Stroke>
<LinearGradientBrush>
<GradientStop Color="#00000000" Offset="0.0"/>
<GradientStop Color="#FF000000" Offset="1.0"/>
</LinearGradientBrush>
</Path.Stroke>
In C#:
var brush = new LinearGradientBrush();
brush.GradientStops.Add(new GradientStop(new Color { A = 0, R = 0, B = 0, G = 0 }, 0.0));
brush.GradientStops.Add(new GradientStop(new Color { A = 255, R = 0, B = 0, G = 0 }, 1.0));
this._path.Stroke = brush;
Also, to address the original question, whether or not the above is what you're looking for, you have a couple of options to split up the Path. Since you know the Data is a PathGeometry composed of PathFigures, you can simply programatically access the segments and create more Path objects. For layout, because each Path itself is a new UIElement whose parent has to measure and arrange it, you need to put all the new Paths into a layout panel that will keep them in the same relative position.
I think there are several ways you could go about this, but one way to absolutely position them back together is to simply lay them out on a canvas with their Canvas.Top and Canvas.Left (or .Right, .Bottom depending on how you're laying them out) set to the relative offsets of the beginning of each segment in the path, and adjust the points so that they are relative to the new upper left corner of the new Path. For example, this
<Path Stroke="Black">
<Path.Data>
<PathGeometry>
<PathFigure>
<LineSegment Point="10,10"/>
<LineSegment Point="20,60"/>
<LineSegment Point="70,60"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
can become something like
<Path Stroke="Black">
<Path.Data>
<PathGeometry>
<PathFigure>
<LineSegment Point="10,10"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
<Path Stroke="Black" Canvas.Top="10" Canvas.Left="10">
<Path.Data>
<PathGeometry>
<PathFigure>
<LineSegment Point="10,50"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
<Path Stroke="Black" Canvas.Top="60" Canvas.Left="20">
<Path.Data>
<PathGeometry>
<PathFigure>
<LineSegment Point="50,0"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
It should be clear how you may do this by constructing several Path's given the PathGeometry object from C# as well, as it sounds like you may not be doing this in XAML from your question. Let me know if it isn't though and I can elaborate more.

Related

Visually split Path into two side-by-side colors in WPF

If I have a rather meandering Path in my WPF app, is there a way I can make it appear as two differently-colored Paths of identical widths side-by-side? I'd rather not try to hand-code the whole thing again with slightly different values. I thought of using a Brush, but the list of Brushes doesn't appear to have one such.
Edit: I want a Path divided sharply by color, even if it curves, like this:
Made a little search, and found that also :
Two-color Path object
Timwi answer :
<StackPanel Orientation="Horizontal">
<StackPanel.LayoutTransform>
<ScaleTransform CenterX="0" CenterY="0" ScaleX="15" ScaleY="15" />
</StackPanel.LayoutTransform>
<Grid Margin="-5,0,0,0">
<Path Fill="Blue" Stroke="Transparent">
<Path.Data>
<PathGeometry>M10,10 C20,10 10,20 20,20 L20,19 C11,19 21,9 10,9</PathGeometry>
<!-- |← original path →| |← generated part →| -->
</Path.Data>
</Path>
<Path Fill="Red" Stroke="Transparent">
<Path.Data>
<PathGeometry>M10,10 C20,10 10,20 20,20 L20,21 C9,21 19,11 10,11</PathGeometry>
<!-- |← original path →| |← generated part →| -->
</Path.Data>
</Path>
</Grid>
</StackPanel>
So "playing" with margin may be much easier that the other options I told you about for what you need.
DropShadowEffect solved my issue.

How ArcSegment works ? Radius not a real radius?

I draw an arc with arcsegment a change its coords (start point and point) programmaticaly. I set a default Size to (50,50). At the screen, the arc really changes (grows when values of start point and point change), but the size is never updated (always 50,50). The MSDN says that size property is the radius of the arc, so why this values are never changed ?
I find a way to calculate the real radius from start, end point and the middle point of the arc and is really different. I wish to change the radius with mouse, but how to do that if the radius property is not a really one (which property to set) ?
Thanks for your help !
<Path Name="ConnecteurPath" Stroke="Black">
<Path.Data>
<PathGeometry>
<PathFigure x:Name="pthFigure" >
<ArcSegment x:Name="arcSeg" IsLargeArc="True"
Size="50, 50"
SweepDirection="Clockwise" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>

Silverlight - Reading path data at runtime

I have a work area (grid) where I add and remove objects at runtime, mostly canvases or stackpanels containing different paths.
When I have dragged 'n' dropped all objects I want to my 'drawing', I want to save the data to the database.
I use XamlWriter.Save() to get the string data and it works "fine", but all Path Data is empty:
XAML for Path Data is not available due to Silverlight runtime limitations
<Path StrokeThickness="0.98">
<Path.Data>
<PathGeometry>
<!-- XAML for Path Data is not available due to Silverlight runtime limitations -->
</PathGeometry>
</Path.Data>
<Path.Stroke>
<SolidColorBrush Color="#FF000000">
<SolidColorBrush.Transform>
<MatrixTransform>
<MatrixTransform.Matrix>
<Matrix />
</MatrixTransform.Matrix>
</MatrixTransform>
</SolidColorBrush.Transform>
<SolidColorBrush.RelativeTransform>
<MatrixTransform>
<MatrixTransform.Matrix>
<Matrix />
</MatrixTransform.Matrix>
</MatrixTransform>
</SolidColorBrush.RelativeTransform>
</SolidColorBrush>
</Path.Stroke>
</Path>
Is there any way around this?
I really need to get the path data to be able to save and then later open and continue working on my 'drawing'.
Help and/or other ideas are very welcome..!
Thanks in advance!
//Anna
If RobSiklos' comment doesn't help, you might have to either serialize that data in another way, or manually post process the XML and add the path data yourself.

How to implement a speech bubble custom border in SL with a movable leader

Check out the following pic. This happens when you expand a folder in Mac OS X from its shortcut on the dock. I'd like to do something very similar in SL. And in case it's difficult to understand - the dock is on the right, with the folder-speech-bubble expanding up & out to the left. The folder contents would be icons out of frame in the upper-left.
The best I've come up with is including a xaml Path that makes up the "leader" portion of the bubble and placing it directly over the border of a canvas. It looks like the following.
The Path, being a separate element, doesn't "integrate" well with the Grid and causes two issues. If you look closely you'll see that there is a slight transparency and the Grid's border is subtly bleeding through. Something else that will crop up, if I use a border thickness > 1, is the line-end caps between the Path border and the Grid border won't be connected, they'll simply overlap looking chunky and unpolished.
What I need is a solution that allows me to slide the leader up & down the speech bubble (depending upon its context) and adapts to the issues explained above. I'd be happy with ideas, examples, and down right full implementations.
You don't have to use the Border control. Just create a Path and shove it and the controls in a Canvas tag to be grouped. Then, the Path will be something like the below:
<Path Canvas.Left="0" Canvas.Top="0" Stroke="DarkGray" StrokeLineJoin="Round" StrokeThickness="2" Fill="Silver" Opacity="0.5">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="0,10" IsClosed="True">
<ArcSegment SweepDirection="Clockwise" Point="10,0" Size="10,10"/>
<LineSegment Point="90,0"/>
<ArcSegment SweepDirection="Clockwise" Point="100,10" Size="10,10"/>
<LineSegment Point="100,90"/>
<ArcSegment SweepDirection="Clockwise" Point="90,100" Size="10,10"/>
<LineSegment Point="10,100"/>
<ArcSegment SweepDirection="Clockwise" Point="0,90" Size="10,10"/>
<LineSegment x:Name="BottomOfCallOut" Point="0,70"/>
<LineSegment Point="-40,50"/>
<LineSegment x:Name="TopOfCallOut" Point="0,30"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
Then just use PointAnimation to move both TopOfCallOut and BottomOfCallOut along the Y-axis. In this example, I've made the base of the callout 40 points, so if you move TopOfCallOut from 0,30 to 0,10, just make sure you also put BottomOfCallOut to 0,50.
I used same approach in TipBubble control (http://www.youpvp.com/blog/post/TipBubble-Tutorial.aspx). It works well in most cases but breaks down if you combine border and transparent background. To make bubble that works in that particular case you'd have to make it with single path. Just combine arc and line segments into one path. Or you could try rounded rectangle callout from Blend 4 SDK.
In case someone still needs a Bubble in Silverlight, I've prepared a reusable control for this purpose.
I'm not allowed to post images here yet, but you can see the pictures, details and download the code from by blog post here: http://mikeshilkov.wordpress.com/2012/01/26/speech-bubble-control-in-sl/

How can I highlight/outline a Visual object in WPF?

If I had a Canvas with n number of Visual objects of any shape or size, how would I highlight/outline a Visual object programmatically?
Is there something built into WPF to help me?
Having read the comments in the other answer -- in which you state that you wish the outline to conform to the shape of the visual -- I can only suggest you take a look at the BitmapEffects. There is one for an Outer Glow effect.
Duplicating the visuals themselves would probably be less efficient, and would probably produce a great number of complications due to other aspects of those items, such as any bindings.
Edit: In .NET 4.0, BitmapEffects property and the BitmapEffect class are obsolete. You'll get an exception thrown. Instead, you now have the System.Windows.Media.Effects.Effect class and its derived classes, along with properties such as Visual.VisualEffect.
Joel has a great suggestion about using BitmapEffects.
However, if you can use .NET 3.5 SP1, I would steer you toward GPU rendered effects. So, instead of using UIElement.BitmapEffect, you would use UIElement.Effect. .NET 3.5 SP1 has two GPU effects built in: BlurEffect and DropShadowEffect. You can also create your own GPU effects ... and this is where you would use ShaderEffect.
Check out Greg Schechter's blog post series for more info.
Here is a piece of code for a mouse over effect that I just implemented a few days ago (it actually shows up sort of like an outer glow bitmap effect due to the ShadowDepth being 0, but not exactly):
<Path
x:Name="mouseOverEffect"
Width="80"
Height="43.916"
Stretch="None"
Fill="#FFFFFFFF"
Opacity="0"
>
<Path.Data>
<PathGeometry FillRule="Nonzero">
<PathFigure IsClosed="True" StartPoint="39.9592899612151,25.9913931634531">
<LineSegment Point="80.0000001464848,43.9159987905149"/>
<LineSegment Point="39.9513899394755,4.97379893856246E-14"/>
<LineSegment Point="1.77635636294422E-15,43.9159987905149"/>
<LineSegment Point="39.9592899612151,25.9913931634531"/>
</PathFigure>
</PathGeometry>
</Path.Data>
<Path.Effect>
<DropShadowEffect
Color="#FFFFFFFF"
BlurRadius="10"
ShadowDepth="0"
/>
</Path.Effect>
</Path>
If you wrap those Visual objects in a Border ... and make the Opacity 0 by default ... then you could programmatically turn the Opacity to 1 whenever you need to.
Does that help?

Resources