碰撞问题:将圆弧的旋转中心放在半圆上并旋转,直到其接触放置圆弧的半圆

问题描述

我以前已经编写了一个代码,允许圆弧绕其给定的中心(14,0)旋转,但是一旦它与另一条曲线接触,圆弧就停止旋转。

当我将圆弧绕(14,0)旋转但不旋转(8.5,0)时,此代码有效

我通过使用linspace()来更改theta,从而将弧的旋转置于while循环内。我使用polyxpoly()查找交集。 while循环的条件是,只要我有空数组,循环就会继续,但是一旦我从polyxpoly()得到一个值,我的循环就会停止。

旋转(14,0)时的代码

clc,clear
R = 5;                     % radius of a circle
r = 10;                     % radius of arc
aa = 60*pi/180;              % arc angle
ap = 0*pi/180;             % arc position angle

% defining the semi-circle about the origin

t = linspace(0,pi);
[x,y] = pol2cart(t,R);      % circle data

% Shifting circle centre to (3.5,0)
x=x+3.5;
y=y+0;

% defining the arc about the origin
t1 = linspace(0,aa)-aa/2+ap;
[x1,y1] = pol2cart(t1,r); % arc data

% shifting arc-lower-end to (14,0)
delx=14-x1(1); % Finding the x difference between arc-lower-end x-coordinate & 14
dely=0-y1(1); % Finding the y difference between arc-lower-end y-coordinate & 0

x1=x1+delx;
y1=y1+dely;

theta =linspace(0,pi,500);
i=1;
xc=[];
yc=[];

while isempty(xc)&& isempty(yc)

% create a matrix of these points,which will be useful in future calculations

v = [x1;y1];

% choose a point which will be the center of rotation

x_center = 14;

y_center = 0;

% create a matrix which will be used later in calculations

center = repmat([x_center; y_center],1,length(x1));

% define a 60 degree counter-clockwise rotation matrix



R = [cos(theta(i)) -sin(theta(i)); sin(theta(i)) cos(theta(i))];

% do the rotation...

s = v - center;     % shift points in the plane so that the center of rotation is at the origin

so = R*s;           % apply the rotation about the origin

vo = so + center;   % shift again so the origin goes back to the desired center of rotation

% this can be done in one line as:

% vo = R*(v - center) + center

% pick out the vectors of rotated x- and y-data

x_rotated = vo(1,:);

y_rotated = vo(2,:);


[xc,yc] = polyxpoly(x_rotated,y_rotated,x,y)
[xc1,yc1] = polyxpoly(x1,y1,y)

i=i+1;
end


% make a plot
plot(x,y)
hold on 

plot(x1,'k-',x_rotated,'r-',x_center,y_center,'bo');

axis equal

以上代码输出

img

当我选择(8.5,0)作为圆弧旋转的中心时,polyxpoly()会在第一个实例中直接为我提供一个防止圆弧旋转的值。

以前,只要执行while循环,弧就保持旋转。当圆弧与半圆接触时,while循环停止执行。但是当我将(8.5,0)用作半圆的旋转中心时(我的要求),while循环未执行,因为polyxpoly()将给出一个值,因为(8.5,0)位于半圆上,因此认情况下为圆弧从开始触及半圈。 有什么方法可以使polyxpoly忽略交点的初始点(8.5,0),以便使弧线绕(8.5,0)旋转

解决方法

polyxpoly对于具有尴尬形状的多边形非常有用,因为数学已为您完成,但与圆形碰撞则有点过分。数学很容易找到解析解决方案。

以原点[0,0]为中心的圆周长上的每个点都满足以下公式:x^2+y^2=R^2

由此,您可以得出满足方程x^2+y^2<=R^2的每个点,无论是在圆内还是在圆的外围。这成为简单的碰撞测试条件。我们只需要在每次迭代时检查弧的最后一点的坐标,并找出它是否满足条件。

在代码中应用,对于最初的问题(围绕[14,0]旋转),它的工作原理与polyxpoly一样好(我怀疑它会更快)。

%%
clc,clear
Rc  = 5;            % radius of a circle
Ra  = 10;           % radius of arc
aa = 60*pi/180;     % arc angle
ap =  0*pi/180;     % arc position angle
cc = [3.5 0] ;      % Circle center coordinates
ao = [14 0 ] ;      % Arc "origin"
% ao = [8.5 0 ] ;      % Arc "origin"

% defining the semi-circle about the origin
[xc,yc] = pol2cart( linspace(0,pi),Rc );  % circle data
% Shifting circle centre to (3.5,0)
xc = xc + cc(1) ;
yc = yc + cc(2) ;

% defining the arc about the origin
[xa,ya] = pol2cart( linspace(0,aa)-aa/2+ap,Ra ) ; % arc data

% shifting arc-lower-end to (14,0) (Arc origin)
xa = xa - xa(1) + ao(1) ;
ya = ya - ya(1) + ao(2) ;

%% make a copy or the arc coordinates (to animate/rotate later)
xar = xa ;
yar = ya ;

%% make a plot
h.fig    = figure;
hold on
% Static elements
h.circle    = plot(xc,yc) ;
h.arcstart  = plot(xa,ya,'k--') ;
h.arcorig   = plot(ao(1),ao(2),'bo') ;
% dynamic element (the moving arc)
h.arcmov    = plot(xar,yar,'g-') ;

axis equal

%% Setup loop parameter
nStep = 500 ;
iStep = 1 ;
theta = linspace(0,pi,nStep);
collision_detected = false ;

%%
while iStep<=nStep && ~collision_detected

    %% counter-clockwise rotation matrix
    Rot = [ cos(theta(iStep)) -sin(theta(iStep)) ;
            sin(theta(iStep)) cos(theta(iStep))  ] ;

    % create a matrix of the arc points,already translated to the origin
    v = [xa-ao(1) ; ya-ao(2)];
    % apply rotation
    v = Rot * v ;
    % apply translation to put the arc back in place
    xar = v(1,:) + ao(1) ;
    yar = v(2,:) + ao(2) ;

    % Determine if the last point of the arc has touched or entered the circle
    % get the coordinate of the last point of the arc,translated so the circle
    % would appear to be centered on the origin
    xp = xar(end) - cc(1) ;
    yp = yar(end) - cc(2) ;

    if (xp^2+yp^2) <= Rc^2
        collision_detected = true ;
    end

    % update display
    set( h.arcmov,'XData',xar,'YData',yar ) ;
    if collision_detected
        set( h.arcmov,'Color','r' )
        h.cp = plot( xar(end),yar(end),'x','LineWidth',2,'MarkerSize',20 ) ;
    end
    drawnow

    iStep = iStep+1 ;

end

说明的结果:

collision animation


现在,这对于您定义的旋转原点的所有位置都适用,除了您感兴趣的旋转原点:[8.5 0]。如果您使用这些旋转原点坐标运行上面编写的脚本,您会看到弧线只是旋转而不会停止。

这是因为在这种配置下,圆弧末端只能以非常特定的旋转角度theta=pi/2刷圆。当圆弧旋转pi/2时,其终点就在圆自身上。该点永远不会在圆内。在pi/2之前或之后的任何旋转角度,该点均不在圆内。

由于我们定义theta = linspace(0,nStep);的方式,因此脚本本身无法检测到此奇异的碰撞点。在我们要尝试的所有theta值中,没有一个是完全pi/2的值。因此,我们从未给脚本提供检测冲突的机会。

有2种解决方法:

第一种方法很简单,但仅针对此问题,可能无法很好地概括。我们只需要在间隔theta上重新定义[0 pi],但是使用数量为 odd 的值,这样就可以确定向量{{1} }就是theta

因此,用以下内容替换pi/2定义:theta足以使脚本解决该特定问题:

collision detected

但是,这是一种解决方法,因为它需要事先知道确切的解决方案,以确保脚本不会丢失它。克服此类步长问题的更通用方法是在条件中包含theta = linspace(0,nStep+1);。 因此,除了使用tolerance定义之外,我们还将在代码之上定义我们可以接受的公差级别,例如:

theta

,我们将碰撞检测条件更改为:

Tolerance = 0.001 ;

以您的示例为例,对于if (xp^2+yp^2) <= (Rc^2+Tolerance) collision_detected = true ; end ,即使不重新定义nSteps=500也足以检测到冲突(实际上,公差为0.0005也可以)。但是请注意,如果将基本步长定义得较大(例如theta),则必须调整公差。

因此,总而言之,我建议对通用代码保留两种实现。在nSteps=100个值中定义Theta并引入公差。