1
\$\begingroup\$

I'm trying to wrap my head around coordinate projection, and can't seem to solve the problem I am having. Here is an illustration of it:

enter image description here

The cubes represent 3d space, and the 2 red lines represent the positions of 3 points (which could be n points). I'm then trying to project these lines onto the green plane shown on the second cube.

My code so far for this is the following:

private List<Vector3> ProjectPoints(List<Vector3> points, Vector3 axis1, Vector3 axis2)
{
    var projectedPoints = new List<Vector3>();

    // first point is already on plane
    projectedPoints.Add(points[0]);

    // blue line
    axis1.Normalize();
    // yellow line
    axis2.Normalize();

    var planeNormal = Vector3.Cross(axis1, axis2);

    float totalRotationAngleSoFar = 0;

    // project remaining points
    for (int i = 1; i < points.Count; i++)
    {
        // get point relative to origin (prev point)
        Vector3 pointRelativeToOrigin = points[i] - points[i - 1];
        Vector3 pointDir = Vector3.Normalize(pointRelativeToOrigin);

        // rotate point by all the angles from previous points, this is so if we had
        // a curve where the points went in on themselve, this rotation would see the
        // curve 'unfolding' into a straight line on the plane
        Vector3 rotationAxis = Vector3.Cross(pointDir, planeNormal);
        Vector3 rotatedPoint = Vector3.Transform(pointRelativeToOrigin, Matrix.CreateFromAxisAngle(rotationAxis, totalRotationAngleSoFar));

        // get rotation axis and min angle between point and plane.
        float minAngleBetweenPointAndPlane = TODO_GetAngleBetweenPointAndPlane();

        // add to total rotation for the next point to use (TODO minus or plus?)
        totalRotationAngleSoFar -= minAngleBetweenPointAndPlane;

        // rotate point in line with plane
        Vector3 projectedPoint = Vector3.Transform(rotatedPoint, Matrix.CreateFromAxisAngle(rotationAxis, minAngleBetweenPointAndPlane));
        projectedPoint += projectedPoints.Last();
        projectedPoints.Add(projectedPoint);
    }

    return projectedPoints;
}

I 'think' this is the right approach, though not 100% sure. Also I've no idea how to calculate TODO_GetAngleBetweenPointAndPlane() with the data I have. I expect you can use the dot product, but I'm not sure what data I would plug in.

\$\endgroup\$
  • \$\begingroup\$ You definitely need to use matrices for projections. Looks like orthogonal projection is what you're trying to achieve. \$\endgroup\$ – Ocelot Oct 16 '16 at 16:41
  • \$\begingroup\$ By orthogonal projection you mean placing the viewpoint above the cube, looking straight down on the green square, then taking the positions from that perspective? In that case, it wouldn't quite get what I want as the dark red line would be going backwards. That's why I tried doing rotations instead so the line would be straightened out also. \$\endgroup\$ – user92679 Oct 16 '16 at 16:42
  • \$\begingroup\$ Sorry then, I just can't understand what you are trying to do. Is this really a projection? My knowledge is limited enough to make me think that projections are usually (and should be) done by matrices. \$\endgroup\$ – Ocelot Oct 16 '16 at 16:53
0
\$\begingroup\$

I figured it out. Answer to my question was this:

// get rotation axis and min angle between point and plane.
var dot = Vector3.Dot(planeNormal, rotatedPointDir);
float angle = (float)Math.Acos(dot);
float minAngleBetweenPointAndPlane;
if (angle >= MathHelper.PiOver2)
    minAngleBetweenPointAndPlane = angle - MathHelper.PiOver2;
else
    minAngleBetweenPointAndPlane = MathHelper.PiOver2 - angle;

As well as storing the rotation matrices (instead of just angle), and also using the signed angle when using CreateFromAxisAngle.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.