Bradley Gray
Bradley Gray

Reputation: 457

c# - Rotating Points About Axis

I currently have code that will generate segment points and at each segment point will generate some points within a short cylinder around the point (in 3D, the segments positions all have a z value of 0.0F (however I'd like to have varying z-values that are in a line - i.e. it's still in a line, but in the line z = 3x for example), but the x, and y are randomised). However currently all the points generated are in a cylinder that is facing upwards, I want to be able to rotate the points such that the cylinder they are 'generated' in is facing in the direction between the two segments. Here's an image of what it should look like vs. what it currently looks like

I found this similar question about rotating points around an axis; I took the answer and used that code for my RotatePoints() function but it doesn't seem to work correctly and I'm not sure why. Below is my psuedo code, what would I need to do get this function working correctly? Is there a better way to do this? The points just need to be generated within a rotated cylinder so would a completely different method be more efficient and easier?

All I have is the location of each segment and each point stored as a Vector3 {x,y,z} in local space.

Psuedo-Code

double radius;
// Generates the positions where the points will be generated around
// These are just the x,y,z positions of the object in world space
Vector3[] segmentLocations = GenerateSegmentPositions(numSegments);

for (int i = 0; i < numSegments; i++) {
    // Generates points in a cylinder facing up the +ve y-axis
    // This works fine        
    Vector3[][] pointsAroundSegment = GeneratePoints(segmentLocations[i], radius);

    if (i != numSegments - 1 && i > 0) {
        // Generate a normalise direction vector for the new direction
        Vector3 newDir = Vector3.Normalise(segmentLocations[i + 1] - segmentLocations[i]);
        double theta = Vector3.AngleBetween(newDir - Vector3.Normalise(segmentLocations[i] - segmentLocations[i - 1]));
        // Rotates points (this currently rotates the points so they 'should' be facing the new direction, I haven't yet modified this to face the halfway point)
        // This doesn't work
        pointsAroundSegment = RotatePoints(pointsAroundSegment, newDir, theta/2);
    } else if (i == numSegments - 1) {
        // Generate final point
        // This works fine
        pointsAboutSegment = GenerateFinalPoint(segmentLocations[i]);
    }
}

// This is the actual rotation function
// RotatePoints() effectively just calls this for each point in the array
public static double[] Rotate(double x, double y, double z, double u, double v, double w, double theta) {
    double[] c = new double[3];
    c [0] = u * (u * x + v * y + w * z) * (1 - Math.Cos (theta)) + x * Math.Cos (theta) + (-w * y + v * z) * Math.Sin (theta);
    c [1] = v * (u * x + v * y + w * z) * (1 - Math.Cos (theta)) + y * Math.Cos (theta) + (w * x - u * z) * Math.Sin (theta);
    c [2] = w * (u * x + v * y + w * z) * (1 - Math.Cos (theta)) + z * Math.Cos (theta) + (-v * x + u * y) * Math.Sin (theta);

    return c;
}

Upvotes: 2

Views: 1332

Answers (1)

Bradley Gray
Bradley Gray

Reputation: 457

Answer courtesy of Poosh;

To rotate the point (x,y,z) about the line through (a,b,c) with the normalised (u^2 + v^2 + w^2 = 1) direction vector by the angle theta use the following function:

public static double[] Rotate(double x, double y, double z, double a, double b, double c, double nu, double nv, double nw, double theta) {
    double[] rP = new double[3];

    rP [0] = (a * (nv * nv + nw * nw) - nu * (b * nv + c * nw - nu * x - nv * y - nw * z)) * (1 - Math.Cos (theta)) + x * Math.Cos (theta) + (-c * nv + b * nw - nw * y + nv * z) * Math.Sin (theta);
    rP [1] = (b * (nu * nu + nw * nw) - nv * (a * nu + c * nw - nu * x - nv * y - nw * z)) * (1 - Math.Cos (theta)) + y * Math.Cos (theta) + (c * nu - a * nw + nw * x - nu * z) * Math.Sin (theta);
    rP [2] = (c * (nu * nu + nv * nv) - nw * (a * nu + b * nv - nu * x - nv * y - nw * z)) * (1 - Math.Cos (theta)) + z * Math.Cos (theta) + (-b * nu + a * nv - nv * x + nu * y) * Math.Sin (theta);

    return rP;
}

Upvotes: 2

Related Questions