Hossein Narimani Rad
Hossein Narimani Rad

Reputation: 32481

Functions with other functions as input using delegates in C#

I have some delegates and a method:

delegate Point Translate(Point p);
delegate Translate Transform(Translate t);

Translate forward = p => new Point(p.X + 1, p.Y);

Question: How can I implement a method like this:

Transform Rotate90 = ??

So that Rotate90 rotates any Translate function 90 clockwise. So:

Point startPoint = new Point(1, 1);
Point endPoint = (Rotate90(forward))(startPoint);
//desired output: Point(1, 0)

EDIT 1: I'm not going to apply Translate functions one by one on a point. What I need is to apply some transformed functions (Translate function that have been rotated or reflexed) on a point.

WHAT I NEED: How can I write a Rotate90 which if I pass it (p=>new Point(p.X+1, p.y)) it returns me a function with the same effect as (p=>new Point(p.X, p.Y-1)).

EDIT 2: Some examples:

Translate forward =         p => new Point(p.X + 1, p.Y);
Translate backward =        p => new Point(p.X - 1, p.Y);
Translate downward =        p => new Point(p.X, p.Y - 1);
Translate runningForward =  p => new Point(p.X + 5, p.Y);

Transform Rotate90Cw = ??

Point samplePoint = new Point(1, 1);

Point p1 = (Rotate90Cw(forward))(samplePoint);          //must be (1,0)
Point p2 = (Rotate90Cw(backward))(samplePoint);         //must be (1,2)
Point p3 = (Rotate90Cw(downward))(samplePoint);         //must be (0,1)
Point p4 = (Rotate90Cw(runningForward))(samplePoint);   //must be (1,-4)
Point p4 = (Rotate90Cw(Rotate90Cw(forward)))(samplePoint);   //must be (0,1)

I need a single Rotate90Cw function that can be applied on any Translate function and returns a proper Translate function. So the effect of applying Rotate90Cw(forward) on a point would be the same as applying downward on a point. And so on...

I'm not going to make a separate Rotate function for every case (e.g. forwardRotated, downwardRotated and ...

Upvotes: 1

Views: 153

Answers (2)

Hossein Narimani Rad
Hossein Narimani Rad

Reputation: 32481

I solve it this way (EDITED):

Translate Rotate90Cw(Translate moveFunction)
{
    return Rotate(moveFunction, Math.PI / 2.0);
}

Translate Rotate(Translate moveFunction, double angle)
{
    Point tempPoint = moveFunction(new Point(0, 0));
    double sin = Math.Sin(angle);
    double cos = Math.Cos(angle);
    return p => new Point(p.X + tempPoint.X * cos + tempPoint.Y * sin,
                           p.Y - tempPoint.X * sin + tempPoint.Y * cos);
}

Check if it is working:

Rotate90Cw(Rotate90Cw(runningForward))(new Point(1, 1)); //output: (-4,0.9999999)
Rotate90Cw(runningForward)(new Point(1, 1));             //output: (1,-4)
Rotate90Cw(backward)(new Point(1, 1));                   //output: (1,2)
Rotate90Cw(downward)(new Point(1, 1));                   //output: (0,1)

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1500525

It's not clear that you actually want two delegates. It seems that really you want one delegate representing an arbitrary transformation from Point to Point - and you can then compose transformations. For example:

delegate Point Transform(Point input);

private static Transform Compose(Transform first, Transform second)
{
    return p => second(first(p));
}

Transform forward = p => new Point(p.X + 1, p.Y);
Transform rotate90 = p => new Point(p.Y, -p.X);
Transform forwardThenRotate = Compose(forward, rotate);

EDIT: It looks like what you actually want is a transform (taking in a transform) along the lines of:

  • Apply the original transform to (0, 0)
  • Rotate the result
  • Translate the incoming point by that much

We can do that easily:

Transform forward = p => new Point(p.X + 1, p.Y);
Transform rotate90 = p => new Point(-p.Y, p.X);
Point forwardRotatedPoint = rotate90(forward(new Point(0, 0));

Transform forwardRotated = p => new Point(forwardRotatedPoint.X + p.X,
                                          forwardRotatedPoint.Y + p.Y);

As I said elsewhere though, you probably actually want a Vector type, which has X and Y components... then you could have several composable concepts:

  • Creating a transformation (point to point) from a vector
  • Rotating one vector to create another
  • Composing transformations

Upvotes: 3

Related Questions