0

I've been trying to generate points along the ring of a 2D disc (both translated and rotated) in 3D space using only the disc's position and normal.

I've been using the following code to generate points and have been testing it in Matlab (but will be utilising this in c#) to check that the points are generated correctly, however it doesn't seem to be generating points correctly.

numPoints = 25;
radius = 1;
pos = [1; 2; 3];
dir = normc([3; 4; 6]); % normalised

function [pointsT, points] = GenerateDiscPoints(numPoints, radius, pos, dir) 
    points = zeros(numPoints, 3);
    pointsT = zeros(numPoints, 3);

    % Angle between points
    angle = 2 * pi / numPoints;

    for i = 1:numPoints+1
        % Current point angle
        theta = angle * i; 

        % Generate point in flat disc (y is vertical axis in Unity)
        x = radius * cos(theta) + pos(1);
        y = 0 + pos(2);
        z = radius * sin(theta) + pos(3);

        % Save points
        points(i, 1) = x;
        points(i, 2) = y;
        points(i, 3) = z;

        % Calculate t value to translate points
        t = (dir(1) * pos(1) - dir(1) * x + dir(2) * pos(2) - dir(2) * y + dir(3) * pos(3) - dir(3) * z) / (dir(1)*dir(1) + dir(2)*dir(2) + dir(3)*dir(3));

        % Translate points to correct location
        xT = x + t*dir(1);
        yT = y + t*dir(2);
        zT = z + t*dir(3);

        % Save translated points
        pointsT(i, 1) = xT;
        pointsT(i, 2) = yT;
        pointsT(i, 3) = zT;
    end

    % Plot
    figure;
    hold all;
    grid on;
    scatter3(points(:,1), points(:,2), points(:,3), 25, 'r');
    scatter3(pointsT(:,1), pointsT(:,2), pointsT(:,3), 25, 'g');
    p3 = line([pos(1) pos(1)+dir(1)], [pos(2) pos(2)+dir(2)], [pos(3) pos(3)+dir(3)]);
    set(p3, 'Color', 'blue');
end

Here's a picture of the output.

The blue line is the normal of the disc, the red points are the points before being translated, and the green points are the points after being translated. To my eye it appears that the translated points don't seem to be generating in a disc that has the normal specified.

What's wrong with my current algorithm? What would a better way to do this be?

Bradley Gray
  • 337
  • 3
  • 10
  • Possible duplicate of [Plotting a normal vector to a plane in matlab](https://stackoverflow.com/questions/35082373/plotting-a-normal-vector-to-a-plane-in-matlab) – dasdingonesin Jul 06 '17 at 10:25
  • Your axis scaling makes it look wrong. Use [`axis equal`](https://de.mathworks.com/help/matlab/ref/axis.html#inputarg_style) – dasdingonesin Jul 06 '17 at 10:28
  • I didn't know about axis equal. Using it made the graph look correct, but I believe what @spug said is correct. My code only produces a projection of the points, therefore it will generate an ellipse rather than a circle. – Bradley Gray Jul 07 '17 at 23:17

1 Answers1

1

A simple linear translation along the direction of dir is insufficient - you'll end up with the projection of the circle on the plane at pos with normal dir, i.e. an ellipse.

You could either:

or

  • Construct an orthogonal basis at pos where one axis is dir.

    Easy way to do this:

    1. Check if the X-axis is parallel to dir - ideally do abs(dot(dir, X)) < 0.8 (assuming both are normalized), so they are not too close to each other

    2. If (1) is true then take dir2 = Y, else dir2 = X.

    3. To create the first basis vector, A = normalize(cross(dir, dir2)).

    4. To create the second, B = cross(dir, A).

    5. Now you can generate points at each value of theta by pos + radius * (A * cos(theta) + B * sin(theta)) (in vector notation).

meowgoesthedog
  • 14,670
  • 4
  • 27
  • 40