Calculate normals from nodes which generate a 3D curve

Hi! I have two matrices:
  • the matrix 'coord' containing the coordinates of nodes (see black nodes in the figure)
  • a matrix 'normals' having in each row the normal N=[a,b,c] (a: first column, b: second column, c: third column) for the first 10 nodes in 'coord'.
How can I determine the normals of the other nodes in 'coord' by following the trend of the nodes (red line in figure)?
load("test_pp.mat")
figure
plot3(coord(:,1),coord(:,2),coord(:,3),'k.','Markersize',20);
hold on
plot3(coord(:,1),coord(:,2),coord(:,3),'-r','LineWidth',2);
hold off
axis equal
EDIT: re-formulated question

5 Comments

Hi @Alberto Acri ,

To calculate the new components of the normal vector (a, b, c) for additional P nodes provided in the 'coord' matrix, start extracting the normal components (a, b, c) for the existing P nodes from the 'circle' cell array. Assuming 'circle' contains the normal components in columns 3, 4, and 5 for each circular geometry, you can access them using indexing by iterating over the new P nodes in the 'coord' matrix. For each new P node, calculate the new normal components based on the circular geometry it belongs to. Then, use vector operations to compute the new normal components. Here is a sample code snippet to illustrate the process:

% Load the data

load('test_p.mat');

% Iterate over new P nodes in 'coord'

for i = 1:size(coord, 1)

    % Find the corresponding circular geometry for the current P node
    % Perform calculations to determine the new normal components (a_new, b_new, c_new)
    % Example calculation (replace with actual computation)
    a_new = 2 * circle{1, 3}; % Example: Doubling the 'a' component
    b_new = circle{1, 4} - 1; % Example: Subtracting 1 from the 'b' component
    c_new = circle{1, 5} + 3; % Example: Adding 3 to the 'c' component
    % Display or store the new normal components for the current P node
    disp(['New Normal Components for Node ', num2str(i), ': ', num2str([a_new, b_new, c_new])]);

end

Please see attached results.

Make sure to customize the calculations based on your specific requirements and data structure. Hope, this answers your question.

Thanks for the answer, but that's not what I want. With your solution, normals are generated all the same for each node in 'coord'. I have reformulated my question.

Hi @ Alberto Acri,

Yes, I can see that. To address your query regarding, “ two matrices: the matrix 'coord' containing the coordinates of nodes (see black nodes in the figure) a matrix 'normals' having in each row the normal N=[a,b,c] (a: first column, b: second column, c: third column) for the first 10 nodes in 'coord'.How can I determine the normals of the other nodes in 'coord' by following the trend of the nodes (red line in figure)?”

So, I modified your code based on your comments. It loads data, initializes matrices, assigns known normals, interpolates normals for nodes without known values, and visualizes the results. It calculates Euclidean distances to find the closest known normal index for interpolation. The code then plots the node coordinates and the interpolated normals as arrows in a 3D plot. This process helps visualize how normals are estimated for nodes based on the nearest known normals, aiding in understanding the spatial distribution of normals across the nodes. Here is updated code,

% Assuming coord is an Nx3 matrix and normals is a 10x3 matrix

num_nodes = size(coord, 1);

known_normals_indices = 1:10; % Indices of known normals

known_normals = normals; % Known normals for first 10 nodes

% Initialize a matrix to hold all normals

all_normals = zeros(num_nodes, 3);

% Assign known normals to their respective indices

all_normals(known_normals_indices, :) = known_normals;

% Interpolate normals for remaining nodes

% We will use linear interpolation based on node indices

for i = 1:num_nodes

    if ismember(i, known_normals_indices)
        continue; % Skip already known indices
    end
    % Find the closest known normal index using Euclidean distance
    distances = sqrt(sum((coord(i,:) - coord(known_normals_indices, :)).^2, 2));
    [~, closest_index] = min(distances); % Get index of closest node
    % Assign interpolated normal (using nearest known normal for simplicity)
    all_normals(i, :) = all_normals(closest_index, :);

end

% Plotting the results

figure;

plot3(coord(:,1), coord(:,2), coord(:,3), 'k.', 'MarkerSize', 20);

hold on;

plot3(coord(:,1), coord(:,2), coord(:,3), '-r', 'LineWidth', 2);

quiver3(coord(:,1), coord(:,2), coord(:,3), ...

         all_normals(:,1), all_normals(:,2), all_normals(:,3), ...
         'b', 'LineWidth', 1); % Plotting normals as arrows

hold off;

axis equal;

xlabel('X-axis');

ylabel('Y-axis');

zlabel('Z-axis');

title('Node Coordinates with Interpolated Normals');

grid on;

Hope, this answers your question.

Hi @ Alberto Acri,
Please see “missing code snippet” updated in my recent post.

Sign in to comment.

Answers (1)

To calculate the “normals” of remaining entries in matrix “coord” we can do interpolation in 3-D space. This can be done using the function “scatteredInterpolant”. This function performs interpolation on scattered data that resides in 2-D or 3-D space. For more information, please refer the below mentioned link.
Then the new “normal” values can be found using the interpolant obtained in the above-mentioned method.
Please find the code below for your reference.
load("test_pp.mat")
known_coords=coord(1:10,:);
F_x = scatteredInterpolant(known_coords(:,1), known_coords(:,2), known_coords(:,3), normals(:,1), 'natural', 'linear');
F_y = scatteredInterpolant(known_coords(:,1), known_coords(:,2), known_coords(:,3), normals(:,2), 'natural', 'linear');
F_z = scatteredInterpolant(known_coords(:,1), known_coords(:,2), known_coords(:,3), normals(:,3), 'natural', 'linear');
% Interpolate normals for the remaining points
remaining_coords = coord(11:end, :);
interp_normals = zeros(size(remaining_coords));
for i = 1:size(remaining_coords, 1)
interp_normals(i, 1) = F_x(remaining_coords(i, 1), remaining_coords(i, 2), remaining_coords(i, 3));
interp_normals(i, 2) = F_y(remaining_coords(i, 1), remaining_coords(i, 2), remaining_coords(i, 3));
interp_normals(i, 3) = F_z(remaining_coords(i, 1), remaining_coords(i, 2), remaining_coords(i, 3));
end
% Combine known and interpolated normals
all_normals = [normals; interp_normals];
% Display results
disp(all_normals)
Hope you find this information helpful.

Products

Release

R2021b

Asked:

on 2 Aug 2024

Answered:

on 14 Aug 2024

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!