如何以特定方式变换曲线

How to transform a curve in a specific way

我有以下曲线(示例数据有些稀疏,但应该能说明问题)。这条曲线上有四个点(用箭头表示),我想将它们用作参考点。这些点需要在箭头种类的方向上移动指定的量(分别为 x1x2x3x4)。始终是这四个位置需要按特定数量移动。 然而,这并不像移动那些特定点那么容易,因为我需要保持曲线的整体形状。

有些约束将始终保持。与 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);

最终目标示例 您可以看到整条曲线如何移动了指定的量但保持了整个形状。

我假设您想通过移动四个点来单独拉伸零件。因此调整范围内的所有点是一个简单的操作。 曲线的整体形状会保持不变,只要满足不重叠的约束条件即可。

当然不像只移动那么容易。但是您可以对曲线的每个部分执行以下操作。

  1. 归零。
  2. 使用计算出的因子拉伸。
  3. 移回零件必须在 最终 曲线中的位置。

这里有一个实现 正是这样做的。 «移动点»的索引在 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-');

这将为您提供以下结果: