Custom Shape
Written by Administrator   
Wednesday, 07 April 2010
Article Index
Custom Shape
Optimising DefiningGeometry
A custom shape example
Repositioning a shape
Choosing a method


Trees - a bigger example

To discuss more of the implementation details of a new Shape we have to have some slightly more interesting geometry to work with. In a simple WPF project Drawing Trees a recursive function was implemented that draws a simple tree figure. The exact shape of the tree is determined by a number of parameters.

The workings of the algorithm are fully described in the article and aren't repeated here. All you really have to know is that the function can be modified to return a collection of lines that form the shape of a tree.


The recursive function MakeTreeGeometry modifies a GeometryGroup object supplied as its first parameter by adding LineGeometry objects that make the shape of a tree. The location of the tree is (x,y), the branches start out at L long and shrink by a factor s at each level of the tree. The first branch is at t degrees and subsequent branches are rotated dt degrees to the right and left. Finally the tree has d levels.

All this is explained in detail in the Drawing Trees project.

private void MakeTreeGeometry(
GeometryGroup tree, 
double x, double y,
double L, double s,
double t, double dt,
int d)
double x1 = x + L *
Math.Cos(t * Math.PI / 180);
double y1 = y - L *
Math.Sin(t * Math.PI / 180);
new LineGeometry(
new Point(x,y),
new Point(x1,y1)));
if (d > 1)
MakeTreeGeometry(tree,x1, y1,
L * s, s, t + dt, dt, d - 1);
MakeTreeGeometry(tree,x1, y1,
L * s, s, t - dt, dt, d - 1);

Now that we can create the Geometry in the form of a GeometryGroup we can implement the new Shape. First we need a GeometryGroup object to hold the lines that make up the tree:

public class Tree : Shape
private GeometryGroup tree
= new GeometryGroup();

Next we need a constructor complete with parameters to specify the shape of the tree. The need for a parameterized constructor is something of a problem and we will return to this later:

public Tree(double x, double y, 
double L, double s,
double t, double dt, int d)
MakeTreeGeometry(tree,x, y,
L, s, t, dt, d);

After the constructor has finished the geometry is safely stored in the GeometryGroup and all that remains is to write the DefiningGeometry get method which couldn't be simpler:

 protected override 
Geometry DefiningGeometry
return tree ;

Now you can create an instance of Tree and render it into a canvas say:

new Tree(200, 200,
50, .8,
90, 15, 4)
{Stroke = Brushes.Black,
StrokeThickness = 2 });

If you try this out the result is a tree as promised.


A tree

So far this all works - but there are some big disadvantages to the implementation.

The most obvious is that the constructor sets up the position of the tree and there are no separate x and y properties that can be set to determine where the tree is after it has been instantiated.


This means that we cannot move the tree and cannot animate it - although why you would want to animate a tree is puzzling - the general point is that shapes should be positionable.





Last Updated ( Wednesday, 07 April 2010 )