Search code examples
c++mathcocos2d-iphonecocos2d-x

Determine point a certain distance away from a line


This is more of a math question than an actual programming question but since I'm using C++ and COCOS2D-X, I opted to post it here.

I'm using CCBezierTo to create a bezier movement that the sprite mySpriteruns. The CCBezierConfig struct accepts three points (CCPoints): controlPoint_1, controlPoint_2, and endPoint. The two controlPoints are the points in which the bezier will curve.

Now here's the question. The controlPoints which I need to create a curve are unknown and can only be acquired by doing a bit of math. These are the variables that are known. Please refer to the diagram below.

A = The start point of the curve
B = The end point of the curve
Line AB = The line created by connecting A and B together
L = The distance between A and B/The length of Line AB
D = The distance between the line and the unknown points

I am trying to look for X and Y. I have already achieved a bit of this but only when the line is either horizontal or vertical:

// From left to right:
ccBezierConfig bezierConfig;
bezierConfig.controlPoint_1 = CCPointMake( A.x + ( L * 0.25f ), A.y + aCertainHeight );
bezierConfig.controlPoint_2 = CCPointMake( A.x + ( L * 0.75f ), A.y - aCertainHeight );
bezierConfig.endPoint = B;

/** CCPointMake( x, y ) is a macro that creates a CCPoint object, which is a point on a plane. 
    It accepts two float values determining the X and Y position of the point.**/

// From top to bottom:
ccBezierConfig bezierConfig;
bezierConfig.controlPoint_1 = CCPointMake( A.x + aCertainWidth, A.y - ( L * 0.25f ) );
bezierConfig.controlPoint_2 = CCPointMake( A.x - aCertainWidth, A.y - ( L * 0.25f ) );
bezierConfig.endPoint = B;

How can I get X and Y if the line is diagonal?

Case 1: Line starts from left to right Case 1: Line starts from left to right

Case 2: Line starts from upper left to lower right Case 2: Line starts from upper left to lower right

Case 3: Line starts from upper right to lower left Case 3: Line starts from upper right to lower left

Thanks in advance.


Solution

  • Step 1: compute the vector from A to B, call it v.

    Step 2: compute a vector perpendicular to that vector, and with unit length. Call it w. In general (-y, x) and (y, -x) are both perpendicular to (x, y). The former points "to the left" and the latter "to the right".

    Step 3: compute X as A + 0.25 * v + D_1 * w and similar for Y.

    I think this all works out as:

    // Using a "point" type for a vector is dodgy, but it works.
    w = CCPointMake((B.y - A.y) / L, -(B.x - A.x) / L);
    X = CCPointMake(
        0.75 * A.x + 0.25 * B.x + D_1 * w.x,
        0.75 * A.y + 0.25 * B.y + D_1 * w.y,
    );
    Y = CCPointMake(
        0.25 * A.x + 0.75 * B.x + D_2 * w.x,
        0.25 * A.y + 0.75 * B.y + D_2 * w.y,
    );
    

    or similar.

    If cocos2d has a separate type for 2-D vectors, use that, you might find that you can write expressions like (B - A)/L and so on.