Search code examples
matlabplotmatlab-figure

How can I update a surf plot in MATLAB?


I try to simulate a robot motion by using a line, 'o', as a robot. I update its motion using set. But I have a problem to update the new position and angle of the robot's view angle. I use surf as a robot view angle, because I want to show color gradients. Now I have to delete the surf plot, and replot it again every time.

How can I update the figure, rather than completely redrawing it every time? enter image description here

This is my code:

    classdef Robot6<handle
    properties
          velocity = 0;                         
          position = [0 0];
          angle=0;

    end
    methods
        function Runn(obj)
             set( gcf,'WindowKeyPressFcn',  @keyboard_down,'CloseRequestFcn', @close_window, 'WindowKeyReleaseFcn', @keyboard_up)
             set( gca,'color', 'white','xlim', [-100, 100],'ylim', [-100, 100])
             robot=line(obj.position(1), obj.position(2),'marker','o');
             hold(gca,'on')        
              program_on = 1;
     
              while program_on         
                userdataStore=[obj.velocity obj.angle obj.position]
                %pause(0.001);
                
                vel = [userdataStore(1)*cosd(userdataStore(2)),userdataStore(1)*sind(userdataStore(2))];
                pos = userdataStore(3:4);
                new_position = pos + vel;
                if (abs(new_position(1)) > 100 || abs(new_position(2)) > 100)
                    new_position = pos;
                end
                obj.position = new_position;
                
                set(robot, 'XData', new_position(1), 'YData', new_position(2));
                %set(orient,'XData', new_position(1)+2*cos(userdataStore(2)), 'YData', new_position(2)+2*sin(userdataStore(2)));   
                %delete(orient)
                x=[new_position(1) new_position(1)+10*cosd(userdataStore(2))+(10*tand(35)*cosd(90-userdataStore(2))) new_position(1)+10*cosd(userdataStore(2))-(10*tand(35)*cosd(90-userdataStore(2)))];
                y=[new_position(2) new_position(2)+10*sind(userdataStore(2))-10*tand(35)*sind(90-userdataStore(2)) new_position(2)+10*sind(userdataStore(2))+10*tand(35)*sind(90-userdataStore(2))];
                z=[100 0 0];
                xv = linspace(min(x), max(x), 1000);
                yv = linspace(min(y), max(y), 1000);
                [X,Y] = meshgrid(xv, yv);
                Z = griddata(x,y,z,X,Y);
                figure(1)
                orient=surf(X, Y, Z);
                grid off
                %set(gca, 'ZLim',[0 500])
                shading interp
                colormap(jet(80))
                view(2)
                pause(1)
                delete(orient)
                pause(0.00000000001)
        
              end
             delete(gcf);
              
             function close_window(~,~)
                program_on = 0;
             end
             
             function keyboard_down(~, event)
                switch event.Key
                    case 'downarrow'
                        obj.velocity = -5;
                    case 'uparrow'
                        obj.velocity = 5;    
                    case 'leftarrow'
                        obj.angle = obj.angle + 6;
                    case 'rightarrow'
                        obj.angle = obj.angle - 6;
                    otherwise
                        disp('unknown key');
                end
             end
             
            function keyboard_up(~,~)
                obj.velocity = 0;
            end
            
        end
        
    end
end

Solution

  • You can do that the same way you update your robot graphic object. Initialise an empty surf object just after you initialise the robot, then in the while loop you only update the surface with set.

    So for your code, just under your lines:

    robot=line(obj.position(1), obj.position(2),'marker','o');
    hold(gca,'on')
    

    declare the empty surface object (it will exist but will not apear at this point because it is empty of data point):

    orient = surf([],[],[]) ;
    

    Then in the main while loop, replace the line:

    orient=surf(X, Y, Z);
    

    with this one:

    set(orient,'XData',X,'YData',Y,'ZData',Z)
    

    That answers your main question on how to update a surf plot instead of redrawing it every time. Note that now you are not recreating a plot at every loop, a lot of the axes and figure properties won't be recalculated at each update, so you can also take all these lines:

    grid off
    %set(gca, 'ZLim',[0 500])
    shading interp
    colormap(jet(80))
    view(2)
    

    out of the main loop and place them right after the surface creation. These properties will stay like that and don't need to be set again at each loop iteration.