📄 polyedit.m
字号:
function p = polyedit(varargin)
%POLYEDIT Polygon editor.
% P = POLYEDIT opens a window and runs the Polygon Editor. This editor
% allows you to draw and modify a polygon using mouse input.
%
% The editor has 4 main mutually exclusive modes:
% ADD: Add vertices in sequence by clicking the left mouse
% button. If you hold the button down, a dashed line will
% preview the new edge until you release. The last vertex
% in sequence is always colored red for reference. Infinite
% vertices may be added by clicking twice outside the axes
% box (to indicate exit and reentry directions).
% MOVE: Move a vertex by clicking and dragging to a new
% location. Only finite vertices may be moved, and they
% must stay within the axes box.
% INSERT: Insert a trivial vertex by clicking on an existing
% side. You may insert onto any side, including an infinite
% one.
% DELETE: Delete a vertex by clicking on it. You may delete only
% finite vertices. Deleting a vertex with an infinite
% neighbor changes the angle at infinity.
%
% To close a polygon, draw the final side by clicking on the first
% vertex in ADD mode or by using the appropriate pushbutton. Once a
% polygon is closed, it remains so; adding in sequence is no longer
% possible. You may continue to move, insert, and delete
% vertices. When you are ready to exit, click on "OK" and the final
% edition of your polygon will be returned in the variable P.
%
% The controls on the right panel of the window allow you to constrain
% the vertices to a grid or to discretize the allowable angles and/or
% lengths.
%
% Q = POLYEDIT(P) starts the editor with the given polygon P loaded.
%
% POLYEDIT(H), where H is the handle of a figure, runs the editor in
% the given figure window. This allows you, for example, to "trace"
% graphics you already have displayed. To do this, make sure you enter
% HOLD ON before running POLYEDIT.
%
% See also the POLYGON class.
% Copyright 2001 by Toby Driscoll.
% $Id: polyedit.m 259 2003-04-01 16:39:46Z driscoll $
fig = [];
poly = [];
for j=1:nargin
arg = varargin{j};
if ishandle(arg) & strcmp(get(arg,'type'),'figure')
fig = arg;
elseif isa(arg,'polygon')
poly = arg;
end
end
if isempty(fig)
% Open a new figure.
fig = figure('vis','off');
figstate = [];
axlim = [-4 4 -4 4];
% Make a reasonable initial size.
un = get(0,'unit');
set(0,'unit','char')
ss = get(0,'screensize');
set(0,'unit',un)
siz = max( 0.65*ss(3:4), [95 36] );
set(fig,'unit','char','pos',[ss(3:4)-siz-[8 4] siz])
set(fig,'closereq',@PEQuit)
else
% Save current state.
turn_off_hold = ~ishold;
figprops = {'unit';'pos';'resizefcn';'pointer';'windowbuttondown';...
'windowbuttonup';'pointer';'menubar';'name';'numbertitle'};
figstate = get(fig,figprops);
axprops = {'unit';'pos';'xgrid';'ygrid'};
axstate = get(gca,axprops);
% Set up.
if ~ishold
cla
axis auto
end
% Reset axes limits?
if strcmp(get(gca,'xlimmode'),'auto') & strcmp(get(gca,'ylimmode'),'auto')
axlim = [-4 4 -4 4];
else
axlim = axis;
end
end
% Set up controls
PE_make_widgets(fig,axlim);
PE_resize_widgets(fig);
data = guidata(fig);
% Initialize with the given polygon, if any.
if ~isempty(poly)
w = vertex(poly);
data.polyvertex = w;
data.polybeta = angle(poly) - 1;
data.isclosed = 1;
data.atinf = zeros(length(w),2);
data.atinf(isinf(w),:) = 1;
data.atinf = data.atinf(:);
data.Edges = plot(poly);
hold on
x = get(data.Edges,'xdata');
y = get(data.Edges,'ydata');
for j = 1:length(w)
data.Vertices(j) = plot(real(w(j)),imag(w(j)),'bo',...
'markerfacecolor','b');
if isinf(w(j))
set(data.Vertices,'user',[ x{j} y{j} ])
else
set(data.Vertices,'user',[ x{j}(1) y{j}(1) ] )
end
end
data.addmode = 'normal';
guidata(fig,data)
set(data.AddButton,'enable','off')
set(data.MoveButton,'value',1)
set(data.FinishButton,'enable','off')
set(data.AcceptButton,'enable','on')
PEMoveMode(fig)
else
set(data.AddButton,'value',1)
PEAddMode(fig)
end
% Let it run (modally, since it has an output value).
set(fig, 'pointer','crosshair','menubar','none',...
'name','Polygon Editor','numbertitle','off','resizefcn',@PE_resize_widgets)
hold on
set(fig,'vis','on')
try
uiwait(fig)
% Retrieve the polygon and assign to output if nonempty.
data = guidata(fig);
P = data.polygon;
if ~isempty(P) | nargout > 0
p = P;
end
catch
errordlg({'Unexpected termination. Last message:',lasterr},...
'PolyEdit error')
P = [];
end
% Clean up the mess.
if isempty(figstate)
% This was a new figure.
delete(fig)
else
set(fig,figprops,figstate)
set(gca,axprops,axstate)
set(data.Vertices,'erasemode','normal')
set(data.Edges,'erasemode','normal')
PEClear(fig)
% This could be destructive in some cases.
delete(findobj(fig,'type','uicontrol'))
delete(data.PreviewLine)
if turn_off_hold
hold off
end
plot(p)
set(gca,'xtickmode','auto','ytickmode','auto')
set(gca,'xticklabelmode','auto','yticklabelmode','auto')
end
% Callback functions.
function PEAddMode(obj,varargin)
data = guidata(obj);
% Can't turn this button off by pushing on it.
if get(data.AddButton,'value')==0
set(data.AddButton,'value',1)
return
end
data.mode = 'Add';
guidata(obj,data)
set(data.InsertButton,'value',0)
set(data.MoveButton,'value',0)
set(data.DeleteButton,'value',0)
set(data.SnapToggle,'enable','on')
set(data.DiscAngToggle,'enable','on')
set(data.DiscLenToggle,'enable','on')
PESnapMode(obj)
PEDiscAngMode(obj)
PEDiscLenMode(obj)
set(data.Figure,'windowbuttondown',@PEAddStart)
set(data.Vertices,'button','','hittest','off','erase','norm')
set(data.Edges,'button','','hittest','off')
function PEInsertMode(obj,varargin)
data = guidata(obj);
% Can't turn this button off by pushing on it.
if get(data.InsertButton,'value')==0
set(data.InsertButton,'value',1)
return
end
data.mode = 'Insert';
guidata(obj,data)
set(data.AddButton,'value',0)
set(data.MoveButton,'value',0)
set(data.DeleteButton,'value',0)
set(data.SnapToggle,'enable','off')
set(data.DiscAngToggle,'enable','off')
set(data.DiscLenToggle,'enable','off')
PESnapMode(obj)
PEDiscAngMode(obj)
PEDiscLenMode(obj)
set(data.Figure,'windowbuttondown','')
set(data.Vertices,'button','','hittest','off','erase','norm')
set(data.Edges,'button',@PEInsert,'hittest','on')
function PEMoveMode(obj,varargin)
data = guidata(obj);
% Can't turn this button off by pushing on it.
if get(data.MoveButton,'value')==0
set(data.MoveButton,'value',1)
return
end
data.mode = 'Move';
guidata(obj,data)
set(data.AddButton,'value',0)
set(data.InsertButton,'value',0)
set(data.DeleteButton,'value',0)
set(data.SnapToggle,'enable','on')
set(data.DiscAngToggle,'enable','off')
set(data.DiscLenToggle,'enable','off')
PESnapMode(obj)
PEDiscAngMode(obj)
PEDiscLenMode(obj)
set(data.Figure,'windowbuttondown','')
set(data.Vertices,'button',@PEMoveStart,'hittest','on','erase','norm')
set(data.Edges,'button','','hittest','off')
function PEDeleteMode(obj,varargin)
data = guidata(obj);
% Can't turn this button off by pushing on it.
if get(data.DeleteButton,'value')==0
set(data.DeleteButton,'value',1)
return
end
data.mode = 'Delete';
guidata(obj,data)
set(data.AddButton,'value',0)
set(data.InsertButton,'value',0)
set(data.MoveButton,'value',0)
set(data.SnapToggle,'enable','off')
set(data.DiscAngToggle,'enable','off')
set(data.DiscLenToggle,'enable','off')
PESnapMode(obj)
PEDiscAngMode(obj)
PEDiscLenMode(obj)
set(data.Figure,'windowbuttondown','')
set(data.Vertices,'button',@PEDelete,'hittest','on')
set(data.Edges,'button','','hittest','off')
function PESnapMode(obj,varargin)
% What to do if snap mode is enabled/disabled.
data = guidata(obj);
if get(data.SnapToggle,'value') & strcmp(get(data.SnapToggle,'enable'),'on')
% Turns off discretization modes.
set(data.DiscAngToggle,'value',0)
set(data.DiscLenToggle,'value',0)
space = str2num(get(data.GridSpaceEdit,'string'));
axlim = axis;
x = axlim(1):space:axlim(2);
y = axlim(3):space:axlim(4);
set(gca,'xticklabelmode','auto','yticklabelmode','auto')
set(gca,'xtick',x,'ytick',y)
% For clarity, keep only about eight of the labels.
N = length(x);
keep = [1,3:ceil((N-1)/8):N-2,N];
xl = get(gca,'xticklabel');
p = min(size(xl,2),4);
xlnew = setstr(ones(N+1,1)*blanks(p));
xlnew(keep,:) = xl(keep,1:p);
N = length(y);
keep = [1,3:ceil((N-1)/8):N-2,N];
yl = get(gca,'yticklabel');
p = min(size(yl,2),4);
ylnew = setstr(ones(N+1,1)*blanks(p));
ylnew(keep,:) = yl(keep,1:p);
% Make it so.
set(gca,'xticklabel',xlnew,'yticklabel',ylnew)
set(gca,'xgrid','on','ygrid','on')
else
set(gca,'xtickmode','auto','xticklabelmode','auto','xgrid','off')
set(gca,'ytickmode','auto','yticklabelmode','auto','ygrid','off')
end
drawnow
function PEDiscAngMode(obj,varargin)
data = guidata(obj);
if get(data.DiscAngToggle,'value') & ...
strcmp(get(data.DiscAngToggle,'enable'),'on')
set(data.SnapToggle,'value',0)
PESnapMode(obj)
end
function PEDiscLenMode(obj,varargin)
data = guidata(obj);
if get(data.DiscLenToggle,'value') & ...
strcmp(get(data.DiscLenToggle,'enable'),'on')
set(data.SnapToggle,'value',0)
PESnapMode(obj)
end
function PEAddStart(obj,varargin)
data = guidata(obj);
%%set(data.PreviewLine,'vis','on')
set(data.Figure,'windowbuttonmotion',@PEAddMove)
set(data.Figure,'windowbuttonup',@PEAddFinish)
PEAddMove(obj)
function PEAddMove(obj,varargin)
data = guidata(obj);
ptrpos = get(data.Axes,'currentpoint');
P = ptrpos(1,1:2);
axlim = axis;
pts = PE_get_clicks(data);
%%x = get(data.Vertices,'xdata');
%%y = get(data.Vertices,'ydata');
%%pts = [x(:),y(:)];
m = size(pts,1);
grid = str2num(get(data.GridSpaceEdit,'string'));
grid = grid * get(data.SnapToggle,'value');
qang = 1/str2num(get(data.AngQuantEdit,'string'));
qang = qang * get(data.DiscAngToggle,'value');
qlen = str2num(get(data.LenQuantEdit,'string'));
qlen = qlen * get(data.DiscLenToggle,'value');
switch data.addmode
case 'normal'
mode = 0;
case 'first'
% Point may not be outside axes box.
P(1) = min(max(P(1),axlim(1)),axlim(2));
P(2) = min(max(P(2),axlim(3)),axlim(4));
mode = 0;
case 'infinite'
% Point may not be inside axes box.
if all(P>axlim([1,3])) & all(P<axlim([2,4]))
[junk,j] = min(abs([P(1)-axlim(1:2);P(2)-axlim(3:4)]'));
P = axlim(j);
end
mode = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -