如何以特定方式变换曲线
How to transform a curve in a specific way
我有以下曲线(示例数据有些稀疏,但应该能说明问题)。这条曲线上有四个点(用箭头表示),我想将它们用作参考点。这些点需要在箭头种类的方向上移动指定的量(分别为 x1
、x2
、x3
和 x4
)。始终是这四个位置需要按特定数量移动。 然而,这并不像移动那些特定点那么容易,因为我需要保持曲线的整体形状。
有些约束将始终保持。与 x2
关联的箭头永远不会与 x1 指定的箭头重叠。 x3
的箭头永远不会超过 x2
的箭头。与 x4
关联的箭头永远不会超过与 x3
关联的箭头。曲线将始终具有这种一般形状,并且将始终在这 4 个点移动。
换句话说,下图中的箭头是该曲线移动方式的代表性示例。
我该怎么做?我的一个想法是拟合某种样条曲线,然后根据这些点以一种优雅的方式以某种方式转换该样条曲线。但是我真的不确定。
这是这个例子在 Matlab 中的数据
x = [6; 7; 7.2; 7.3; 7.5; 7.7; 7.9; 8; 8.13; 8.2; 8.21; 8.31; 8.4; 8.41; 8.45; 8.47; 8.5; 8.6; 8.8; 9; 9.6; 10];
y = [0; 0.01; 0.02; 0.1; 1; 1.1; 0.9; 0.6; 0; -0.5; -1; -1.1; -0.93; -0.9; -0.7; -0.6; -0.2; 0; 0.1; 0.12; 0; 0];
plot(x,y);
最终目标示例
您可以看到整条曲线如何移动了指定的量但保持了整个形状。
我假设您想通过移动四个点来单独拉伸零件。因此调整范围内的所有点是一个简单的操作。 曲线的整体形状会保持不变,只要满足不重叠的约束条件即可。
当然不像只移动点那么容易。但是您可以对曲线的每个部分执行以下操作。
- 归零。
- 使用计算出的因子拉伸。
- 移回零件必须在 最终 曲线中的位置。
这里有一个实现 正是这样做的。 «移动点»的索引在 ind
中指定,相对于 x 轴的移动量在 val
中指定。
x = [6; 7; 7.2; 7.3; 7.5; 7.7; 7.9; 8; 8.13; 8.2; 8.21; 8.31; 8.4; 8.41; 8.45; 8.47; 8.5; 8.6; 8.8; 9; 9.6; 10];
y = [0; 0.01; 0.02; 0.1; 1; 1.1; 0.9; 0.6; 0; -0.5; -1; -1.1; -0.93; -0.9; -0.7; -0.6; -0.2; 0; 0.1; 0.12; 0; 0];
ind = [ 3; 6; 12; 21]; % The indexes of points to be moved
val = [0.1; -0.1; -0.2; -0.8]; % Value/amount of movement
% Extend scope to beginning and end of data
i = [1,ind',length(x)]; % All the bounds
v = [0;val;0]; % Movements of all bounds
% Split original curve in parts and store them in a cell array
orig = cell(1,length(i)-1); % preallocation
for n = 1:(length(i)-1)
orig{n} = [x(i(n):i(n+1)),y(i(n):i(n+1))];
end
% Stretch the parts and move them to the correct position
new = cell(size(orig)); % preallocation
for n = 1:length(orig)
a = orig{n}(1,1); % first x value
b = orig{n}(end,1); % last x value
p = (b-a+v(n+1)-v(n))/(b-a); % factor to stretch
xn = ((orig{n}(:,1)-a)*p)+a+v(n); % calculate new x positions
new{n} = [xn,orig{n}(:,2)]; % add result to cell-array
end
% Put the parts together
% Simple concenation creates double entries at moving points,
% therefore the first part is added outside the loop.
% Preallocation is omitted on purpose.
xn = new{1}(:,1);
yn = new{1}(:,2);
for n = 2:length(new)
xn = [xn;new{n}(2:end,1)]; %#ok<AGROW>
yn = [yn;new{n}(2:end,2)]; %#ok<AGROW>
end
% Display data
figure; hold on;
plot(x(ind),y(ind),'ro'); % Plot original points
plot(x,y,'b.-'); % Plot original curve
plot(x(ind)+val,y(ind),'go'); % Plot new points
plot(xn,yn,'k.-'); % Plot new curve
legend('Original points','Original curve','New points','New curve');
% Plot the new parts separately
%hold all;
%for n = 1:length(new)
% nc = plot(new{n}(:,1),new{n}(:,2));
%end
这将为您提供以下结果:
根据要求: 为了更好地理解发生了什么,下面的代码是一个简化版本,只将最后一个点移动给定数量的 value
。
x = [6; 7; 7.2; 7.3; 7.5; 7.7; 7.9; 8; 8.13; 8.2; 8.21; 8.31; 8.4; 8.41; 8.45; 8.47; 8.5; 8.6; 8.8; 9; 9.6; 10];
y = [0; 0.01; 0.02; 0.1; 1; 1.1; 0.9; 0.6; 0; -0.5; -1; -1.1; -0.93; -0.9; -0.7; -0.6; -0.2; 0; 0.1; 0.12; 0; 0];
value = -1; % the last point will be shifted by this value
p = (x(end)-x(1)+value)/(x(end)-x(1));
% Override of p
%p = 2.0; % p=2.0 will double the length
%p = 0.5; % p=0.5 will halve the length
x2 = ((x-x(1)) * p) + x(1);
figure; hold on;
plot(x,y,'*-');
plot(x2,y,'ro-');
这将为您提供以下结果:
我有以下曲线(示例数据有些稀疏,但应该能说明问题)。这条曲线上有四个点(用箭头表示),我想将它们用作参考点。这些点需要在箭头种类的方向上移动指定的量(分别为 x1
、x2
、x3
和 x4
)。始终是这四个位置需要按特定数量移动。 然而,这并不像移动那些特定点那么容易,因为我需要保持曲线的整体形状。
有些约束将始终保持。与 x2
关联的箭头永远不会与 x1 指定的箭头重叠。 x3
的箭头永远不会超过 x2
的箭头。与 x4
关联的箭头永远不会超过与 x3
关联的箭头。曲线将始终具有这种一般形状,并且将始终在这 4 个点移动。
换句话说,下图中的箭头是该曲线移动方式的代表性示例。
我该怎么做?我的一个想法是拟合某种样条曲线,然后根据这些点以一种优雅的方式以某种方式转换该样条曲线。但是我真的不确定。
这是这个例子在 Matlab 中的数据
x = [6; 7; 7.2; 7.3; 7.5; 7.7; 7.9; 8; 8.13; 8.2; 8.21; 8.31; 8.4; 8.41; 8.45; 8.47; 8.5; 8.6; 8.8; 9; 9.6; 10];
y = [0; 0.01; 0.02; 0.1; 1; 1.1; 0.9; 0.6; 0; -0.5; -1; -1.1; -0.93; -0.9; -0.7; -0.6; -0.2; 0; 0.1; 0.12; 0; 0];
plot(x,y);
最终目标示例
您可以看到整条曲线如何移动了指定的量但保持了整个形状。
我假设您想通过移动四个点来单独拉伸零件。因此调整范围内的所有点是一个简单的操作。 曲线的整体形状会保持不变,只要满足不重叠的约束条件即可。
当然不像只移动点那么容易。但是您可以对曲线的每个部分执行以下操作。
- 归零。
- 使用计算出的因子拉伸。
- 移回零件必须在 最终 曲线中的位置。
这里有一个实现 正是这样做的。 «移动点»的索引在 ind
中指定,相对于 x 轴的移动量在 val
中指定。
x = [6; 7; 7.2; 7.3; 7.5; 7.7; 7.9; 8; 8.13; 8.2; 8.21; 8.31; 8.4; 8.41; 8.45; 8.47; 8.5; 8.6; 8.8; 9; 9.6; 10];
y = [0; 0.01; 0.02; 0.1; 1; 1.1; 0.9; 0.6; 0; -0.5; -1; -1.1; -0.93; -0.9; -0.7; -0.6; -0.2; 0; 0.1; 0.12; 0; 0];
ind = [ 3; 6; 12; 21]; % The indexes of points to be moved
val = [0.1; -0.1; -0.2; -0.8]; % Value/amount of movement
% Extend scope to beginning and end of data
i = [1,ind',length(x)]; % All the bounds
v = [0;val;0]; % Movements of all bounds
% Split original curve in parts and store them in a cell array
orig = cell(1,length(i)-1); % preallocation
for n = 1:(length(i)-1)
orig{n} = [x(i(n):i(n+1)),y(i(n):i(n+1))];
end
% Stretch the parts and move them to the correct position
new = cell(size(orig)); % preallocation
for n = 1:length(orig)
a = orig{n}(1,1); % first x value
b = orig{n}(end,1); % last x value
p = (b-a+v(n+1)-v(n))/(b-a); % factor to stretch
xn = ((orig{n}(:,1)-a)*p)+a+v(n); % calculate new x positions
new{n} = [xn,orig{n}(:,2)]; % add result to cell-array
end
% Put the parts together
% Simple concenation creates double entries at moving points,
% therefore the first part is added outside the loop.
% Preallocation is omitted on purpose.
xn = new{1}(:,1);
yn = new{1}(:,2);
for n = 2:length(new)
xn = [xn;new{n}(2:end,1)]; %#ok<AGROW>
yn = [yn;new{n}(2:end,2)]; %#ok<AGROW>
end
% Display data
figure; hold on;
plot(x(ind),y(ind),'ro'); % Plot original points
plot(x,y,'b.-'); % Plot original curve
plot(x(ind)+val,y(ind),'go'); % Plot new points
plot(xn,yn,'k.-'); % Plot new curve
legend('Original points','Original curve','New points','New curve');
% Plot the new parts separately
%hold all;
%for n = 1:length(new)
% nc = plot(new{n}(:,1),new{n}(:,2));
%end
这将为您提供以下结果:
根据要求: 为了更好地理解发生了什么,下面的代码是一个简化版本,只将最后一个点移动给定数量的 value
。
x = [6; 7; 7.2; 7.3; 7.5; 7.7; 7.9; 8; 8.13; 8.2; 8.21; 8.31; 8.4; 8.41; 8.45; 8.47; 8.5; 8.6; 8.8; 9; 9.6; 10];
y = [0; 0.01; 0.02; 0.1; 1; 1.1; 0.9; 0.6; 0; -0.5; -1; -1.1; -0.93; -0.9; -0.7; -0.6; -0.2; 0; 0.1; 0.12; 0; 0];
value = -1; % the last point will be shifted by this value
p = (x(end)-x(1)+value)/(x(end)-x(1));
% Override of p
%p = 2.0; % p=2.0 will double the length
%p = 0.5; % p=0.5 will halve the length
x2 = ((x-x(1)) * p) + x(1);
figure; hold on;
plot(x,y,'*-');
plot(x2,y,'ro-');
这将为您提供以下结果: