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

## Move a tree

Now we have to solve the problem of repositioning a tree after the instance has been constructed. There are a number of possible solutions to this problem.

#### Recreate the geometry

The simplest is to simply recreate the geometry each time a position property is changed. For example, by adding two properties X and Y (which again should be dependency properties) we can simply clear the GeometryGroup and recreate the tree at its new location:

`private double _X;public double X{ get{return _X;} set {  _X = value;  tree.Children.Clear();  MakeTreeGeometry(tree, _X, Y,                      L, s, t, dt, d); }}private double _Y;public double Y{ get { return _Y; } set {  _Y = value;  tree.Children.Clear();  MakeTreeGeometry(tree, X, _Y,                      L, s, t, dt, d); }}`

To make this work we also need to change the constructor so that it creates a tree at a default X,Y position and stores all of the parameters in suitable properties so that they can be reused:

`public  double L { get; set; }public double s { get; set; }public double t { get; set; }public double dt { get; set; }public int d { get; set; }`
`public Tree(double L, double s,         double t, double dt, int d){ this.L = L; this.s = s; this.t = t; this.dt = dt; this.d = d; MakeTreeGeometry(tree,0, 0,              L, s, t, dt, d);}`

Now we can create a tree as follows:

`canvas1.Children.Add(new Tree(    50, .8, 90, 15, 6)      {X=50,Y=150,        Stroke = Brushes.Black,           StrokeThickness = 2 });`

This approach works but it is clearly not a good thing to have to recreate the geometry each time - with complex geometry this would slow down an animation loop for example.

#### Translate the geometry

How else could we implement the setting of the location of a geometry object?

One alternative would be to fix up the location of each geometry object in the GeometryGroup. For example, you could modify the set functions to update each of the LineGeometry objects in the tree shape:

`private double _X;public double X{ get{return _X;} set {  double shift = value-_X;  _X = value;  foreach (LineGeometry G in                         tree.Children)  {   G.StartPoint=new Point(     G.StartPoint.X+shift,               G.StartPoint.Y);   G.EndPoint=new Point(     G.EndPoint.X+ shift,               G.EndPoint.Y);  } }}private double _Y;public double Y{ get { return _Y; } set {  double shift = value- _Y;  _Y = value;  foreach (LineGeometry G                    in tree.Children)  {   G.StartPoint = new Point(     G.StartPoint.X,         G.StartPoint.Y+shift);   G.EndPoint = new Point(     G.EndPoint.X,         G.EndPoint.Y+shift);  } }}`

Basically what happens is that we compute the shift needed in to move the geometry to the new position and apply this to every object in the collection. In this case the method works and even looks reasonable but this is because there is only a single type of geometry in the collection. In a more general case we would have to examine each type in the collection and implement the shift as required - and this is not a good idea.

#### Transform the geometry

After introducing the idea of a shift you might be thinking that the obvious thing to do is to use the Shape Transform property. This could be set to move the object to a new location in one simple operation.Unfortunately this would result in your custom Shape having a Transform property that wasn't the identity when it was at a location other than (0.0). This too is not a good idea - but the geometry also has a Transform property and as the geometry isn't public we are free to use this without confusing the outside world.

Implementing this idea turns out to be surprisingly easy. All we have to do is set a new transformation each time one of the positional properties is changed:

`private double _X;public double X{ get{return _X;} set {  _X = value;  tree.Transform =     new TranslateTransform(_X, _Y); }}private double _Y;public double Y{ get { return _Y; } set {  _Y = value;  tree.Transform =     new TranslateTransform(_X, _Y); }}`

<ASIN:0470502266>

<ASIN:0672330636>

<ASIN:0470539437>

<ASIN:0596800959>

Last Updated ( Wednesday, 07 April 2010 )