mirror of
https://bitbucket.org/Mattrixwv/octavefunctions.git
synced 2025-12-06 18:53:57 -05:00
Added file to plot a Bezier curve and an example script
This commit is contained in:
95
BezierExample.m
Normal file
95
BezierExample.m
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
% Bezier example
|
||||||
|
|
||||||
|
% This goes in a file named BezierExample.m
|
||||||
|
|
||||||
|
close all
|
||||||
|
clear all
|
||||||
|
|
||||||
|
x_nodes = [];
|
||||||
|
y_nodes = [];
|
||||||
|
|
||||||
|
% Initialize figure window
|
||||||
|
|
||||||
|
figure
|
||||||
|
hold on
|
||||||
|
xlim([0 1])
|
||||||
|
ylim([0 1])
|
||||||
|
|
||||||
|
% Collect nodes
|
||||||
|
|
||||||
|
disp('Click several points on curve. Hit enter to exit')
|
||||||
|
index = 1;
|
||||||
|
while(true)
|
||||||
|
[x,y,button] = ginput(1);
|
||||||
|
|
||||||
|
if (isempty(x))
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
if (button ~= 1)
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
% Add the new point and plot the new line segment
|
||||||
|
|
||||||
|
x_nodes(index) = x(1);
|
||||||
|
y_nodes(index) = y(1);
|
||||||
|
if (index > 1)
|
||||||
|
plot(x_nodes(index-1:index),y_nodes(index-1:index))
|
||||||
|
end
|
||||||
|
|
||||||
|
index = index + 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
% Points have been entered. Build the collection of nodes and control
|
||||||
|
% points that define the curve
|
||||||
|
|
||||||
|
number_curves = length(x_nodes) - 1;
|
||||||
|
bezier_points = cell(number_curves,4);
|
||||||
|
for k = 1:number_curves
|
||||||
|
|
||||||
|
% Insert the nodes
|
||||||
|
|
||||||
|
bezier_points{k,1} = [x_nodes(k) y_nodes(k)];
|
||||||
|
bezier_points{k,4} = [x_nodes(k+1) y_nodes(k+1)];
|
||||||
|
|
||||||
|
% Create the control points
|
||||||
|
|
||||||
|
if (k == 1)
|
||||||
|
bezier_points{k,2} = [x_nodes(1) y_nodes(1)] + ([x_nodes(2) y_nodes(2)] - [x_nodes(1) y_nodes(1)])/3;
|
||||||
|
else
|
||||||
|
|
||||||
|
% Compute positions for control points. Arbitrarily, they will be
|
||||||
|
% collinear with the node in between and 1/3 of the way to the next
|
||||||
|
% node
|
||||||
|
|
||||||
|
vector_1 = [x_nodes(k) y_nodes(k)] - [x_nodes(k-1) y_nodes(k-1)];
|
||||||
|
length_1 = norm(vector_1);
|
||||||
|
vector_1 = vector_1/length_1;
|
||||||
|
|
||||||
|
vector_2 = [x_nodes(k) y_nodes(k)] - [x_nodes(k+1) y_nodes(k+1)];
|
||||||
|
length_2 = norm(vector_2);
|
||||||
|
vector_2 = vector_2/length_2;
|
||||||
|
|
||||||
|
vector_sum = vector_1 + vector_2;
|
||||||
|
n = vector_sum/norm(vector_sum);
|
||||||
|
|
||||||
|
% If vector_1 X vector_2 is negative, reverse the direction of n
|
||||||
|
|
||||||
|
if ((vector_1(1)*vector_2(2) - vector_2(1)*vector_1(2)) < 0)
|
||||||
|
n = -n;
|
||||||
|
end
|
||||||
|
n_p = [-n(2) n(1)];
|
||||||
|
|
||||||
|
bezier_points{k-1,3} = [x_nodes(k) y_nodes(k)] + n_p*length_1/3;
|
||||||
|
bezier_points{k,2} = [x_nodes(k) y_nodes(k)] - n_p*length_2/3;
|
||||||
|
|
||||||
|
if (k == (number_curves))
|
||||||
|
|
||||||
|
bezier_points{k,3} = [x_nodes(number_curves+1) y_nodes(number_curves+1)] + ...
|
||||||
|
([x_nodes(number_curves) y_nodes(number_curves)] - [x_nodes(number_curves+1) y_nodes(number_curves+1)])/3;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
PlotBezier(bezier_points)
|
||||||
184
PlotBezier.m
Normal file
184
PlotBezier.m
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
function PlotBezier( bezier_points )
|
||||||
|
% Display the Bezier curve
|
||||||
|
|
||||||
|
% This goes in a file named PlotBezier.m
|
||||||
|
|
||||||
|
% Clear the children of the current axes
|
||||||
|
|
||||||
|
cla
|
||||||
|
|
||||||
|
% Define the array of parametervectors as a column vector, so calculation
|
||||||
|
% of points on the Bezier curve can be done in one statement
|
||||||
|
|
||||||
|
t = (0:0.05:1)';
|
||||||
|
|
||||||
|
number_segments = size(bezier_points,1);
|
||||||
|
for k = 1:number_segments
|
||||||
|
P0 = bezier_points{k,1};
|
||||||
|
P1 = bezier_points{k,2};
|
||||||
|
P2 = bezier_points{k,3};
|
||||||
|
P3 = bezier_points{k,4};
|
||||||
|
|
||||||
|
% Compute the points on this curve segment and plot them
|
||||||
|
|
||||||
|
bezier = ((1 - t).^3)*P0 + (3*t.*(1 - t).^2)*P1 + (3*t.^2.*(1 - t))*P2 + t.^3*P3;
|
||||||
|
plot(bezier(:,1),bezier(:,2))
|
||||||
|
hold on
|
||||||
|
|
||||||
|
% Plot dotted lines first so they will be behind the nodes and control
|
||||||
|
% points and thus not intercept the clicks on the nodes and control
|
||||||
|
% points
|
||||||
|
|
||||||
|
plot([P0(1) P1(1)],[P0(2) P1(2)],':')
|
||||||
|
plot([P2(1) P3(1)],[P2(2) P3(2)],':')
|
||||||
|
|
||||||
|
% Plot the nodes and control points
|
||||||
|
|
||||||
|
plot(P0(1),P0(2),'o','MarkerFaceColor','k','ButtonDownFcn',@ClickMarker)
|
||||||
|
|
||||||
|
plot(P1(1),P1(2),'o','ButtonDownFcn',@ClickMarker)
|
||||||
|
plot(P2(1),P2(2),'o','ButtonDownFcn',@ClickMarker)
|
||||||
|
end
|
||||||
|
|
||||||
|
% Plot the last node
|
||||||
|
|
||||||
|
plot(P3(1),P3(2),'o','MarkerFaceColor','k','ButtonDownFcn',@ClickMarker)
|
||||||
|
|
||||||
|
% Set the limits
|
||||||
|
|
||||||
|
xlim([0 1])
|
||||||
|
ylim([0 1])
|
||||||
|
function ClickMarker(source,event)
|
||||||
|
set(ancestor(source,'figure'),'WindowButtonMotionFcn',{@DragMarker,source})
|
||||||
|
set(ancestor(source,'figure'),'WindowButtonupFcn',@StopDragging)
|
||||||
|
end
|
||||||
|
|
||||||
|
function DragMarker(figure,event,source)
|
||||||
|
|
||||||
|
% Get current axes and coordinates of the screen point
|
||||||
|
|
||||||
|
h1=gca;
|
||||||
|
coordinates=get(h1,'currentpoint');
|
||||||
|
coordinates = coordinates(1,1:2);
|
||||||
|
|
||||||
|
% Find the closest node or control point. This code is simplistic in the
|
||||||
|
% sense that it always takes the nearest node or control point. If a node
|
||||||
|
% or control point is dragged near another node or control point, then the
|
||||||
|
% other one will be moved.
|
||||||
|
|
||||||
|
segment_index = -1;
|
||||||
|
node_control_index = -1;
|
||||||
|
distance = Inf;
|
||||||
|
for m = 1:size(bezier_points,1)
|
||||||
|
for n = 1:4
|
||||||
|
if (isinf(distance))
|
||||||
|
distance = norm(bezier_points{m,n}-coordinates);
|
||||||
|
segment_index = m;
|
||||||
|
node_control_index = n;
|
||||||
|
else
|
||||||
|
new_distance = norm(bezier_points{m,n}-coordinates);
|
||||||
|
if (new_distance < distance)
|
||||||
|
distance = new_distance;
|
||||||
|
segment_index = m;
|
||||||
|
node_control_index = n;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% Modify the nodes and control points
|
||||||
|
|
||||||
|
old_point = bezier_points{segment_index,node_control_index};
|
||||||
|
bezier_points{segment_index,node_control_index} = coordinates;
|
||||||
|
|
||||||
|
% For an intermediate node, the coodinates are stored twice. Update the
|
||||||
|
% other copy
|
||||||
|
|
||||||
|
if (segment_index < number_segments && node_control_index == 4)
|
||||||
|
bezier_points{segment_index+1,1} = coordinates;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (1 < segment_index && node_control_index == 1)
|
||||||
|
bezier_points{segment_index-1,4} = coordinates;
|
||||||
|
end
|
||||||
|
|
||||||
|
% Moving a node or control point causes movement of other control points.
|
||||||
|
% If a node is moved, the control points on either side need to be moved. If a
|
||||||
|
% control point is moved, its partner acros the node must be moved
|
||||||
|
|
||||||
|
if (node_control_index == 1 || node_control_index == 4)
|
||||||
|
|
||||||
|
% Node was moved. Move attached control points
|
||||||
|
|
||||||
|
translation_vector = bezier_points{segment_index,node_control_index} - old_point;
|
||||||
|
|
||||||
|
if (segment_index == 1 && node_control_index == 1)
|
||||||
|
bezier_points{segment_index,2} = bezier_points{segment_index,2} + translation_vector;
|
||||||
|
elseif (segment_index == number_segments && node_control_index == 4)
|
||||||
|
bezier_points{segment_index,3} = bezier_points{segment_index,3} + translation_vector;
|
||||||
|
else
|
||||||
|
if (node_control_index == 1)
|
||||||
|
bezier_points{segment_index,2} = bezier_points{segment_index,2} + translation_vector;
|
||||||
|
bezier_points{segment_index-1,3} = bezier_points{segment_index-1,3} + translation_vector;
|
||||||
|
else
|
||||||
|
bezier_points{segment_index+1,2} = bezier_points{segment_index+1,2} + translation_vector;
|
||||||
|
bezier_points{segment_index,3} = bezier_points{segment_index,3} + translation_vector;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
|
||||||
|
% Control point was moved. Rotate its partner
|
||||||
|
|
||||||
|
if ((segment_index == 1 && node_control_index == 2) || (segment_index == number_segments && node_control_index == 3))
|
||||||
|
|
||||||
|
% No partner. Nothing else to do
|
||||||
|
|
||||||
|
else
|
||||||
|
new_point = bezier_points{segment_index,node_control_index};
|
||||||
|
if (node_control_index == 2)
|
||||||
|
|
||||||
|
% Rotate previous control point
|
||||||
|
|
||||||
|
rotation_center = bezier_points{segment_index,1};
|
||||||
|
other_control_point = bezier_points{segment_index-1,3};
|
||||||
|
else
|
||||||
|
|
||||||
|
% Rotate next control point
|
||||||
|
|
||||||
|
rotation_center = bezier_points{segment_index,4};
|
||||||
|
other_control_point = bezier_points{segment_index+1,2};
|
||||||
|
end
|
||||||
|
|
||||||
|
new_vector = new_point - rotation_center;
|
||||||
|
new_vector = new_vector/norm(new_vector);
|
||||||
|
old_vector = old_point - rotation_center;
|
||||||
|
old_vector = old_vector/norm(old_vector);
|
||||||
|
|
||||||
|
cos_theta = sum(old_vector.*new_vector);
|
||||||
|
sin_theta = old_vector(1)*new_vector(2) - new_vector(1)*old_vector(2);
|
||||||
|
rotation_matrix = [cos_theta -sin_theta;sin_theta cos_theta];
|
||||||
|
|
||||||
|
other_control_point = other_control_point - rotation_center;
|
||||||
|
|
||||||
|
rotated_other_control_point = (rotation_matrix*(other_control_point'))' + rotation_center;
|
||||||
|
|
||||||
|
if (node_control_index == 2)
|
||||||
|
bezier_points{segment_index-1,3} = rotated_other_control_point;
|
||||||
|
else
|
||||||
|
bezier_points{segment_index+1,2} = rotated_other_control_point;
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% Plot the updated curve
|
||||||
|
|
||||||
|
PlotBezier(bezier_points);
|
||||||
|
|
||||||
|
end
|
||||||
|
function StopDragging(figure,event)
|
||||||
|
set(figure,'WindowButtonMotionFcn','')
|
||||||
|
set(figure,'WindowButtonUpFcn','')
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user