Logo
programming4us
programming4us
programming4us
programming4us
Home
programming4us
XP
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server
programming4us
Windows Phone
 
Windows Phone

Vector Graphics : Bézier Curves

- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019
3/26/2011 9:20:40 PM
Pierre Etienne Bézier (1910–1999) was an engineer at the French automobile company Renault from 1933 to 1975. During the 1960s the company started switching over from designing car bodies with clay to using computer-assisted design. The system required mathematical descriptions of curves that engineers could manipulate without knowing the underlying mathematics. From this work came the curve that now bears Pierre Bézier’s name.

The Bézier curve is a spline, which is a type of curve used to approximate discrete data with a smooth continuous function. Silverlight supports the standard two-dimensional form of the cubic Bézier curve but also a quadratic Bézier curve that is somewhat simpler and faster.

The quadratic Bézier curve is defined by three points, commonly denoted as p0, p1, and p2. The curve starts at p0 and ends at p2. The point p1 is known as a control point. The curve usually does not pass through p1. Instead, p1 functions like a magnet pulling the curve towards it. At p0, the curve is tangent to (and in the same direction as) the line from p0 to p1, and at p3 the curve is tangent to (and in the same direction as) the line from p2 to p3.

Perhaps the best way to become familiar with Bézier curves is to experiment with them. The QuadraticBezier program draws a single Bézier curve but lets you manipulate the three points to see what happens.

The XAML file assembles four Path elements and a Polyline in the single-cell Grid. The first Path is the quadratic Bézier itself. Notice that p0 is provided by the StartPoint property of PathFigure, while p1, and p2 correspond to the Point1 and Point2 properties of QuadraticBezierSegment:

Example 1. Silverlight Project: QuadraticBezier File: MainPage.xaml (excerpt)
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Path Stroke="{StaticResource PhoneForegroundBrush}"
StrokeThickness="2">
<Path.Data>
<PathGeometry>
<PathFigure x:Name="pathFig"
StartPoint="100 100">
<QuadraticBezierSegment x:Name="pathSeg"
Point1="300 250"
Point2="100 400" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>

<Polyline Name="ctrlLine"
Stroke="{StaticResource PhoneForegroundBrush}"
StrokeDashArray="2 2"
Points="100 100, 300 250, 100 400" />

<Path Name="pt0Dragger"
Fill="{StaticResource PhoneAccentBrush}"
Opacity="0.5">
<Path.Data>
<EllipseGeometry x:Name="pt0Ellipse"
Center="100 100"
RadiusX="48"
RadiusY="48" />
</Path.Data>
</Path>

<Path Name="pt1Dragger"
Fill="{StaticResource PhoneAccentBrush}"
Opacity="0.5">
<Path.Data>
<EllipseGeometry x:Name="pt1Ellipse"
Center="300 250"
RadiusX="48"
RadiusY="48" />
</Path.Data>
</Path>

<Path Name="pt2Dragger"
Fill="{StaticResource PhoneAccentBrush}"
Opacity="0.5">
<Path.Data>
<EllipseGeometry x:Name="pt2Ellipse"
Center="100 400"
RadiusX="48"
RadiusY="48" />
</Path.Data>
</Path>
</Grid>


The Polyline element draws a dotted line from the two end points to the control point. The remaining three Path elements are “draggers,” that is, they let you drag any of the three points. The initial screen looks like this:



The code-behind file provides all the dragging logic. Because Silverlight for Windows Phone does not support bindings for properties not defined by FrameworkElement derivatives, I wasn’t able to hook all the corresponding points together in the XAML file. Instead, they have to be set individually in the Manipulation overrides:

Example 2. Silverlight Project: QuadraticBezier File: MainPage.xaml.cs (excerpt)
protected override void OnManipulationStarted(ManipulationStartedEventArgs args)
{
if (args.OriginalSource == pt0Dragger ||
args.OriginalSource == pt1Dragger ||
args.OriginalSource == pt2Dragger)
{
args.ManipulationContainer = ContentPanel;
args.Handled = true;
}
base.OnManipulationStarted(args);
}

protected override void OnManipulationDelta(ManipulationDeltaEventArgs args)
{
Point translate = args.DeltaManipulation.Translation;

if (args.OriginalSource == pt0Dragger)
{
pathFig.StartPoint = Move(pathFig.StartPoint, translate);
ctrlLine.Points[0] = Move(ctrlLine.Points[0], translate);
pt0Ellipse.Center = Move(pt0Ellipse.Center, translate);
args.Handled = true;
}
else if (args.OriginalSource == pt1Dragger)
{
pathSeg.Point1 = Move(pathSeg.Point1, translate);
ctrlLine.Points[1] = Move(ctrlLine.Points[1], translate);
pt1Ellipse.Center = Move(pt1Ellipse.Center, translate);
args.Handled = true;
}
else if (args.OriginalSource == pt2Dragger)
{
pathSeg.Point2 = Move(pathSeg.Point2, translate);
ctrlLine.Points[2] = Move(ctrlLine.Points[2], translate);
pt2Ellipse.Center = Move(pt2Ellipse.Center, translate);
args.Handled = true;
}
base.OnManipulationDelta(args);
}

Point Move(Point point, Point translate)
{
return new Point(point.X + translate.X, point.Y + translate.Y);
}


Being a quadratic, this version of the Bézier curve makes only a single turn, and it is extremely well behaved:



If you ever need them, the parametric formulas used to construct the quadratic Bézier are:



for t = 0 to 1, where p0 = (x0, y0) and so forth.

The cubic Bézier spline is more standard, and has two control points rather than just one. The curve is defined by four points commonly labeled p0, p1, p2, and p3. The curve begins at p0 and ends at p3. At p0 the curve is tangent to (and in the same direction as) a line from p0 to p1, and at p3 the curve is tangent to the line from p3p2. The parametric equations describing the curve are: to



For the CubicBezier program I took a little different approach. In an attempt to simplify it just a bit, I defined a UserControl derivative named PointDragger. The PointDragger.xaml file defines a visual tree consisting of just a Grid containing a Path with an Opacity of 0.5 and an EllipseGeometry with no Center point:

Example 3. Silverlight Project: CubicBezier File: PointDragger.xaml
<UserControl
x:Class="CubicBezier.PointDragger"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Grid x:Name="LayoutRoot">
<Path Fill="{StaticResource PhoneAccentBrush}"
Opacity="0.5">
<Path.Data>
<EllipseGeometry x:Name="ellipseGeometry"
RadiusX="48"
RadiusY="48" />
</Path.Data>
</Path>
</Grid>
</UserControl>

The code-behind file defines a dependency property named Point of type Point, and fires a PointChanged event when the value changes. The property-changed handler is also responsible for setting the value on the EllipseGeometry defined in the XAML file:

Example 4. Silverlight Project: CubicBezier File: PointDragger.xaml.cs (excerpt)
public partial class PointDragger : UserControl
{
public static readonly DependencyProperty PointProperty =
DependencyProperty.Register("Point",
typeof(Point),
typeof(PointDragger),
new PropertyMetadata(OnPointChanged));
public event RoutedPropertyChangedEventHandler<Point> PointChanged;

public PointDragger()
{
InitializeComponent();
}

public Point Point
{
set { SetValue(PointProperty, value); }
get { return (Point)GetValue(PointProperty); }
}

. . .

static void OnPointChanged(DependencyObject obj,
DependencyPropertyChangedEventArgs args)
{
(obj as PointDragger).OnPointChanged((Point)args.OldValue,
(Point)args.NewValue);
}

protected virtual void OnPointChanged(Point oldValue, Point newValue)
{
ellipseGeometry.Center = newValue;

if (PointChanged != null)
PointChanged(this,
new RoutedPropertyChangedEventArgs<Point>(oldValue, newValue));
}
}


The PointDragger class also handles its own Manipulation events, which (compared with the ones in QuadraticBezier) become very simple:

Example 5. Silverlight Project: CubicBezier File: PointDragger.xaml.cs (excerpt)
protected override void OnManipulationStarted(ManipulationStartedEventArgs args)
{
args.ManipulationContainer = VisualTreeHelper.GetParent(this) as UIElement;
args.Handled = true;
base.OnManipulationStarted(args);
}

protected override void OnManipulationDelta(ManipulationDeltaEventArgs args)
{
Point translate = args.DeltaManipulation.Translation;
this.Point = new Point(this.Point.X + translate.X, this.Point.Y + translate.Y);
args.Handled = true;
base.OnManipulationDelta(args);
}


The MainPage.xaml file defines a Path with a BezierSegment, two dotted Polyline elements for the tangent lines, and four instances of PointDragger. The BezierSegment class defines properties named Point1, Point2, and Point3 for the two control points and the endpoint:

Example 6. Silverlight Project: CubicBezier File: MainPage.xaml (excerpt)
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Path Stroke="{StaticResource PhoneForegroundBrush}"
StrokeThickness="2">
<Path.Data>
<PathGeometry>
<PathFigure x:Name="pathFig"
StartPoint="100 100">
<BezierSegment x:Name="pathSeg"
Point1="300 100"
Point2="300 400"
Point3="100 400" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>

<Polyline Name="ctrl1Line"
Stroke="{StaticResource PhoneForegroundBrush}"
StrokeDashArray="2 2"
Points="100 100, 300 100" />

<Polyline Name="ctrl2Line"
Stroke="{StaticResource PhoneForegroundBrush}"
StrokeDashArray="2 2"
Points="300 400, 100 400" />

<local:PointDragger x:Name="pt0Dragger"
Point="100 100"
PointChanged="OnPointDraggerPointChanged" />

<local:PointDragger x:Name="pt1Dragger"
Point="300 100"
PointChanged="OnPointDraggerPointChanged" />

<local:PointDragger x:Name="pt2Dragger"
Point="300 400"
PointChanged="OnPointDraggerPointChanged" />

<local:PointDragger x:Name="pt3Dragger"
Point="100 400"
PointChanged="OnPointDraggerPointChanged" />
</Grid>


The initial screen looks like this:



Notice the PointChanged event handlers on the PointDragger controls. Implementing that handler is pretty much the only thing left for MainPage.xaml.cs to do:

Example 7. Silverlight Project: CubicBezier File: MainPage.xaml.cs (excerpt)
void OnPointDraggerPointChanged(object sender,
RoutedPropertyChangedEventArgs<Point> args)
{
Point translate = new Point(args.NewValue.X - args.OldValue.X,
args.NewValue.Y - args.OldValue.Y);
if (sender == pt0Dragger)
{
pathFig.StartPoint = Move(pathFig.StartPoint, translate);
ctrl1Line.Points[0] = Move(ctrl1Line.Points[0], translate);
}
else if (sender == pt1Dragger)
{
pathSeg.Point1 = Move(pathSeg.Point1, translate);
ctrl1Line.Points[1] = Move(ctrl1Line.Points[1], translate);
}
else if (sender == pt2Dragger)
{
pathSeg.Point2 = Move(pathSeg.Point2, translate);
ctrl2Line.Points[0] = Move(ctrl2Line.Points[0], translate);
}
else if (sender == pt3Dragger)
{
pathSeg.Point3 = Move(pathSeg.Point3, translate);
ctrl2Line.Points[1] = Move(ctrl2Line.Points[1], translate);
}
}

Point Move(Point point, Point translate)
{
return new Point(point.X + translate.X, point.Y + translate.Y);
}


As you play around with the program, you might notice that the curve always stays confined within a four-side polygon defined by the two end points and the two control points. (It’s called a “convex hull” in Bézier circles.). This version of the Bézier curve is a cubic, so the curve can make two turns:



Besides QuadraticBezierSegment and BezierSegment to define single Bézier curves, you can also use PolyQuadraticBezierSegment and PolyBezierSegment for defining a series of Bézier curves. Each curve begins at the point the previous one ends. Each of these classes contains a property named Points of type PointCollection.

For PolyQuadraticBezierSegment, the number of Point objects in the Points collection must be a multiple of 2. The first, third, fifth, and so forth members of the collection are control points. For PolyBezierSegment, the number of points is a multiple of 3.

When connecting multiple Bézier curves, the end point of one curve becomes the begin point of the next curve. The composite curve is smooth at this point only if that point and the two control points on either side are collinear, that is, lie on the same line.

Other -----------------
- Vector Graphics : The Versatile PathGeometry
- Vector Graphics : Grouping Geometries
- Vector Graphics : Geometries and Transforms
- Vector Graphics : The Path Element
- Vector Graphics : Dynamic Polygons
- Vector Graphics : The Stretch Property
- Vector Graphics : Polygon and Fill
- Vector Graphics : Caps, Joins, and Dashes
- Vector Graphics : Polylines and Custom Curves
- Vector Graphics : Overlapping and ZIndex
 
 
Top 10
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
 
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server