How to get point of a figure (using callbacks in GUI) when the point is inside a region that previously has been “patched”?

◇◆丶佛笑我妖孽 提交于 2020-01-14 05:07:26

问题


I am using patch in order to draw inside an ellipse into a figure I have created in gui environment.

Normally, I get figures' points (coordinates) by clicking (using callback functions). It works properly when the point I want to grab is not inside an ellipse that I have previously plotted (applying patch).

What should I do after applying patch in order to be able to get a point that is inside some ellipse after I have drawn it? Thanks a lot!


回答1:


Here's a way to solve your problem:

First we draw a point followed by a patch that "covers" it. In this example the patch is transparent, and still the point behind it cannot be selected.

(this part of the code is taken from MATLAB's example for patch)

close all force; clear variables; clc;
h = plot(3,6,'o')
hold on;

xdata = [2     2     0     2     5;
         2     8     2     4     5;
         8     8     2     4     8];
ydata = [4     4     4     2     0;
         8     4     6     2     2;
         4     0     4     0     0];
cdata = [15     0     4     6    10;
         1     2     5     7     9;
         2     3     0     8     3];
p = patch(xdata,ydata,cdata,'Marker','o',...
          'FaceColor','flat')

If you run this code, you should get an output along the lines of:

h =
  174.0110

p =
  175.0105

Which shows the handles assigned to each child of the axes.

To get some more insight, you add this additional code:

axes_children = get(gca,'Children')
disp(['Type of "point" plot: ' get(h,'type')]);
disp(['Type of "patch" plot: ' get(p,'type')]);

The output of which is:

axes_children =

  175.0105
  174.0110

Type of "point" plot: line
Type of "patch" plot: patch

Notice the order of the elements: 175.0105 (i.e. the patch) is higher in the list - this is very important, because you cannot select an object that is obscured by another object.

In case you have multiple points\patches you can simply reposition the patches below the points using something like this:

for ind1=1:length(axes_children)
    if strcmp(get(axes_children(ind1),'type'),'patch')
        uistack(axes_children(ind1),'bottom');
    end
end

This will make the point(s) selectable and also preserve the order of the patches in case they overlap each other.

Edit

Here's an extended example of the some mouse tracking code that I have compiled for your problem using idea from UndocumentedMatlab. It may give you some more ideas...

function init()
close all force; clear variables; clc;
%// Initialize the figure with a listener:
h = figure('WindowButtonMotionFcn',@windowMotion);
%// Add a "static" text label:
col = get(h,'color');
uicontrol('Style','text', 'Pos',[0,0,300,30],'Tag','lbl',...
          'Background',col, 'HorizontalAlignment','left');

axes('units','pix'); hold all;
for i=1:3
    X = 5*rand(100,1);
    plot(X,rand*X + rand(100,1),'.');
end

    xdata = [2     2     0     2     5;
             2     8     2     4     5;
             8     8     2     4     8]/2;
    ydata = [4     4     4     2     0;
             8     4     6     2     2;
             4     0     4     0     0]/2;
    cdata = [5     0     4     6    10;
             1     2     5     7     9;
             2     3     0     8     3];
    patch(xdata,ydata,cdata,'Marker','o',...
              'FaceColor','interp');

drawnow;

datacursormode on;
end

function windowMotion(hObject,eventData,varargin)
   persistent inCallback;   
   %// If you want to do something complex inside the callback, the
   %// inCallback lines makes sure that only 1 instance of the callback is
   %// being executed at a time.
   if ~isempty(inCallback), return;  end
   inCallback = true;

   lbl = findobj('Tag','lbl');

   try
    currPos = get(gcf,'CurrentPoint');
    ax_pos = get(gca,'Position');

    %// Test if the mouse pointer is inside the axes:
    if (currPos(1)>ax_pos(1) && currPos(1)<ax_pos(1)+ax_pos(3)) && ...
       (currPos(2)>ax_pos(2) && currPos(2)<ax_pos(2)+ax_pos(4)) 

        %// Find all possible
        possible_points_obj = findobj(gca,'Type','line');
        %// SOME LOGIC TO FIND THE CORRECT points_obj
        %// In this example it will look only in the last-plotted group of
        %// points - RED. This can be extended to loop over all "line"
        %// objects and select the closest point of all.
        correct_points_obj = possible_points_obj(1);

        X=get(correct_points_obj,'XData')'; ...'
        Y=get(correct_points_obj,'YData')'; ...'
        XScale=diff(get(gca,'XLim'));
        YScale=diff(get(gca,'YLim'));

        currPosinAx = (currPos - ax_pos(1:2))./ax_pos(3:4).*[XScale YScale];

        r=(((X-currPosinAx(1))./XScale).^2+((Y-currPosinAx(2))./YScale).^2);
        [~,i]=min(r);

        %// Here you put whatever you want to do with the point you found
        set(lbl,'String',{['The closest point to the pointer is at: ('...
                            num2str(X(i)) ',' num2str(Y(i)) '),'];
        ['and belongs to handle: ' num2str(correct_points_obj)]});    
    else
        set(lbl,'String','Mouse is outside axes'); 
    end
   catch
       % error trapping here
   end
   drawnow;
   inCallback = [];
end  % myCallbackFcn1


来源:https://stackoverflow.com/questions/25229506/how-to-get-point-of-a-figure-using-callbacks-in-gui-when-the-point-is-inside-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!