使粒子在圆圈内随机移动

时间:2016-03-15 14:20:02

标签: matlab animation matlab-figure simulate

我试图使绘制的点在已知半径和中心的圆内移动。目前我能够在边界内生成点,但现在我需要让它们移动。

我有以下脚本来生成粒子的初始位置。

function [particle_gen] = generate(n,centre,radius)
    %generates n particles in a circle with specified centre and radius

    angle = 2 * pi * rand(n,1);
    r = radius * sqrt(rand(n,1));
    X = r.*cos(angle) + centre(1);
    Y = r.*sin(angle) + centre(2);
    plot(X,Y,'.k')
end

我想为它们设置动画,使粒子以恒定的速度沿直线行进,直到它们撞到圆形边界并反弹。我需要这一切都发生在同一个情节中。

2 个答案:

答案 0 :(得分:10)

好的,这个问题有几个方面,我将分别解决。

更新绘图对象

就创建情节和更新情节值的后勤而言,您可以使用MATLAB's handle graphics完成所有这些操作。如果您创建绘图对象,则可以使用returned handle绘图来更新绘图。

plt = plot(x, y, 'k.');
set(plt, 'XData', newx, 'YData', newy)

在您的情况下,newxnewy值将在循环中计算,然后您可以分配它们。通过这样做,您不会不断创建新的图形对象,而使用MATLAB可能会非常昂贵。

由于您正在进行大量计算,因此您每次都需要使用drawnow来强制MATLAB渲染图形。

粒子轨迹

您需要计算要更新绘图的xnewynew值。您可以通过多种方式确定这些轨迹,但我在此提出了一种方法。

  1. 应用置换。使用速度和方向,您可以将位移应用于每个粒子。
  2. 确定点是否在圆圈之外。如果位移将点放在圆外(基本方程here),那么我们需要将它放回圆中。如果圆圈外没有任何点,请返回步骤1.
  3. 对于圆圈外的每个点,找到其路径与圆圈的交点。使用this solution作为参考,这是一项非常简单的练习。
  4. 此时查找圆的切线。同样,这是微不足道的,因为我们可以从圆的中心到圆上的交点画一条线。该线斜率的负倒数是交点处曲线的切线斜率。通过将其与交叉点相结合,我们得到了一条线的等式。
  5. 反映在此切线之间的圆圈外的点到"反弹"它会回到圆圈中。可以使用equations provided here执行线上某点的反射。
  6. 示例解决方案

    我已经实施了上述步骤。虽然这可能不是计算效率最高的方法,但它提供了所需的结果。

    function bounce(npts, vmin, vmax, radius, center)
    
        % Initial direction/velocity of the points
        direction = rand(npts, 1) * 2 *pi;
        velocity = (rand(npts, 1) * (vmax - vmin)) + vmin;
    
        % Create random starting locations within the circle
        theta = rand(npts, 1) * 2*pi;
        r = radius * sqrt(rand(npts, 1));
    
        XY = [r .* cos(theta(:)) + center(1), ...
              r .* sin(theta(:)) + center(2)];
    
        % Initial plot objects
        hfig = figure('Color', 'w');
        hax = axes('Parent', hfig);
    
        % Plot the dots as black markers
        hdots = plot(XY(:,1), XY(:,2), ...
                    'Parent', hax, ...
                    'Marker', '.', ...
                    'Color', 'k', ...
                    'LineStyle', 'none', ...
                    'MarkerSize', 12);
    
        hold(hax, 'on')
        axis(hax, 'equal')
    
        % Plot the circle as a reference
        t = linspace(0, 2*pi, 100);
        plot(radius * cos(t) + center(1), ...
             radius * sin(t) + center(2))
    
        % Keep simulating until we actually close the window
        while ishghandle(hfig);
            % Determine new dot locations
            [XY, direction] = step(XY, direction, velocity, radius, center);
    
            % Update the dot plot to reflect new locations
            set(hdots, 'XData', XY(:,1), 'YData', XY(:,2))
    
            % Force a redraw
            drawnow
        end
    end
    
    function [XYnew, direction] = step(XY, direction, velocity, radius, center)
        % Compute the next position of the points
        DX = [cos(direction(:)) .* velocity, ...
              sin(direction(:)) .* velocity];
        XYnew = XY + DX;
    
        % Now check that they are all inside circle
        isOutside = sum(bsxfun(@minus, XYnew, center).^2, 2) > radius^2;
    
        % The ones that are outside should "bounce" back into the circle
        if any(isOutside)        
            orig  = XY(isOutside,:);
            new   = XYnew(isOutside,:);
            delta = -DX(isOutside,:);
    
            % Find intersection of this path with the circle
            % Taken from: https://math.stackexchange.com/a/311956
            a = sum(delta.^2, 2);
            b = sum(2 .* delta .* bsxfun(@minus, orig, center), 2);
            c = sum(bsxfun(@minus, orig, center).^2, 2) - radius^2;
    
            t = (2 * c) ./ (-b + sqrt(b.^2 - 4 .* a .* c)); 
            xintersect = orig(:,1) + delta(:,1) .* t;
            yintersect = orig(:,2) + delta(:,2) .* t;
    
            % Get tangent at this intersection (slope/intercept form)
            m = - 1 ./ ((yintersect - center(2)) ./ (xintersect - center(1)));
            b = yintersect - m .* xintersect;
    
            % "Reflect" outside points across the tangent line to "bounce" them
            % Equations from: https://stackoverflow.com/a/3307181/670206
            d = (new(:,1) + (new(:,2) - b) .* m) ./ (1 + m.^2);
    
            XYnew(isOutside,1) = 2 * d - new(:,1);
            XYnew(isOutside,2) = 2 .* d .* m - new(:,2) + 2 .* b;
    
            % Recompute the direction of the particles that "bounced"
            direction(isOutside) = atan2(XYnew(isOutside,2) - yintersect, ...
                                         XYnew(isOutside,1) - xintersect);
        end
    end
    

    结果

    通过运行以下命令,我可以获得以下结果。

    bounce(100, 0.01, 0.2, 5, [0 0]);
    

    enter image description here

答案 1 :(得分:0)

这不是一个小问题。您当前的方法为您提供初始起始位置。您还需要生成起始“速度”,我将其称为VXVY

也就是说,存储X,Y位置数组以及VXVY方向数组,其中VXVY的每一行都有一个常量规范。然后,您会在每次迭代时按相应的X,YVX递增每个位置VY,然后检查您是否在墙上,然后更改VX和{{1对于点击墙壁的方式,它们会“弹回”它。

希望这能让你开始!祝你好运。