function [RespObj,StatusStr] = showmargin(RespObj,IndShow,All)
%SHOWMARGIN  Displays stability margins on NICPLOT response.
%
%   [RESPOBJ,STATUS] = SHOWMARGIN(RESPOBJ,INDSHOW) plots the margin display for
%   the systems with indices INDSHOW, or all systems if INDSHOW=[].
%
%   [RESPOBJ,STATUS] = SHOWMARGIN(RESPOBJ,INDSHOW,'all') plots all margins
%   for the systems with indices INDSHOW, or all systems if INDSHOW=[].
%
%   See also NICPLOT.

%   Authors: Karen Gondoly, 9-30-96
%            Pascal Gahinet 12-99
%   Revised: Adam DiVergilio
%   Copyright 1986-2000 The MathWorks, Inc. 
%   $Revision: 1.9 $   $Date: 2000/06/14 20:09:40 $

StatusStr = '';
AllProps = get(RespObj,'undocumented');
ResponseHandles = AllProps.ResponseHandles;
ResponseType = AllProps.ResponseType;

%---IndShow is a row vector of which systems need to be plotted
%--- (if empty, plot margins for all systems)
if nargin<2 | isempty(IndShow)
   IndShow = (1:length(ResponseHandles));
end

%---Retrieve (or compute) the margin values (will be in correct units)
if (nargin<3) | (All==0)
   MarginVals = pvget(RespObj,'StabilityMarginValue');
   All = 0;
else
   MarginVals = pvget(RespObj,'AllStabilityMarginValue');
   All = 1;
end

%---System loop
for ctSys=IndShow
   %---Get response handles for this system
   RH1 = ResponseHandles{ctSys}{1};
   Freqs = RespObj.Frequency{ctSys};
   SystemName = MarginVals(ctSys).System;
   %---For AllMargin display, we also have the sample time
   if All
      SampleTime = MarginVals(ctSys).Ts;
   else
      SampleTime = 0;  %---SampleTime is not used for minimum margin display
   end

   %---Determine individual model visibility
   OnModels = (strcmp(AllProps.SystemVisibility(ctSys),'on') & AllProps.SelectedModels{ctSys});
   ArraySize = size(OnModels);

   %---Model loop (skip if no margins are availble)
   for ctModel=1:prod(size(RH1))
      %---Get margin values for this model
      if All
         Margins = MarginVals(ctSys).Margins(ctModel);
      else
         Margins = [];
         if ~isempty(MarginVals(ctSys).GainMargin)
            Margins.Stable      = MarginVals(ctSys).Stable(ctModel);
            Margins.GainMargin  = MarginVals(ctSys).GainMargin(ctModel);
            Margins.PhaseMargin = MarginVals(ctSys).PhaseMargin(ctModel);
            Margins.DelayMargin = [];
            Margins.GMFrequency = MarginVals(ctSys).GMFrequency(ctModel);
            Margins.PMFrequency = MarginVals(ctSys).PMFrequency(ctModel);
            Margins.DMFrequency = [];
            Margins.DMResponse  = [];
         end
      end
      if ~isempty(Margins)
         %---System string
          ArrayLoc = rguihelper('ind2sub',ArraySize,ctModel);
          SystemStr = rguihelper('labelsystem',SystemName,1,1,ArrayLoc,[1 1],ArraySize,ResponseType);
         %---Render---%
          [RH1{ctModel},Status] = localDrawSM(Margins,SampleTime,RH1{ctModel},OnModels(ctModel),SystemStr,RespObj,Freqs{ctModel});
         %---Keep track of warnings
          if length(Status), StatusStr = Status; end
      end
   end

   %---Store response handles
   ResponseHandles{ctSys}{1} = RH1;
end

%---Update RespObj
RespObj.response = pvset(RespObj.response,'ResponseHandles',ResponseHandles);


%%%%%%%%%%%%%%%
% localDrawSM %
%%%%%%%%%%%%%%%
function [RH,Status] = localDrawSM(Margins,SampleTime,RH,VisOn,SystemStr,RespObj,Frequency)
% Draw stability margins

Status = '';

%---Margin values
Gm    = Margins.GainMargin;
GmABS = unitconv(Gm,RespObj.MagnitudeUnits,'abs');
Wcg   = Margins.GMFrequency;
Pm    = Margins.PhaseMargin;
Wcp   = Margins.PMFrequency;
Dm    = Margins.DelayMargin;  % AllMargin display only
Wcd   = Margins.DMFrequency;  % AllMargin display only
DmR   = Margins.DMResponse;   % AllMargin display only
All   = ~isempty(Dm);         % Flag for AllMargin
if isnan(Margins.Stable)
   Stable = 'N/A';
elseif Margins.Stable
   Stable = 'Yes';
else
   Stable = 'No';
end
IsDT = (SampleTime~=0);  % (AllMargin display only)

%---Convert discrete-time delay margins to seconds (AllMargin display only)
if IsDT
   Dm = abs(SampleTime)*Dm;
end

%---Handle storage
Hg = [];
Hp = [];

%---Get line info
ResponseLine = findobj(RH,'Tag','LTIresponseLines');
PlotAxes = get(ResponseLine,'Parent');
PhaseData = get(ResponseLine,'Xdata');
GainData = get(ResponseLine,'Ydata');
CC = get(ResponseLine,'Color');
LC = localConnectorColor(PlotAxes);

%---Visibility
if VisOn
   Visible = 'on';
   InfWarning = 'Infinite stability margins are not displayed.';
else
   Visible = 'off';
   InfWarning = '';
end

%---0dB line
GmLine = unitconv(0,'dB',RespObj.MagnitudeUnits);
Hg(end+1) = line([NaN;NaN],[GmLine;GmLine],...
   'Parent',PlotAxes,'Tag','StabilityMarginMarker',...
   'Visible',Visible,'HandleVisibility','off','HitTest','off',...
   'Color',LC,'LineStyle','-.','UserData',0);
uistack(Hg(:),'bottom');

%---Treat very large margins as Inf
Gm(abs(log10(GmABS))>10) = Inf;

%---Don't render infinite margins and update status text if any exist
idx = isinf(Gm);
if any(idx)
   Status = InfWarning;
   Gm(idx) = [];
   Wcg(idx) = [];
end

%---Determine which margins are with range
InRange1 = Wcg>=Frequency(1);
InRange2 = Wcg<=Frequency(end);
InRange = InRange1 & InRange2;
WcgDisp = Wcg;
Wcg(InRange1==0) = Frequency(1);
Wcg(InRange2==0) = Frequency(end);

%---Snap X to nearest phase crossing
GmPlotP = interp1(Frequency,PhaseData(:),Wcg);
if strncmpi(RespObj.PhaseUnits,'d',1)
   GmPlotP = 360*round((GmPlotP(:)-180)/360) + 180;
else
   GmPlotP = 2*pi*round((GmPlotP(:)-pi)/(2*pi)) + pi;
end
%---Snap Y to actual Gm values
if strncmpi(RespObj.MagnitudeUnits,'d',1)
   GmPlotM = -Gm(:);
else
   GmPlotM = 1./Gm(:);
end

%---Render gain margins
for n=1:length(Gm)
   %---Display string
    Udstr = {SystemStr;...
       sprintf('Gain margin (%s): %0.3g',RespObj.MagnitudeUnits,Gm(n));...
       sprintf('At frequency (%s): %0.3g',RespObj.FrequencyUnits,WcgDisp(n));...
       sprintf('Closed-loop stable? %s',Stable)};
   %---Render
    Hg(end+1) = line([GmPlotP(n);GmPlotP(n)],[GmPlotM(n);GmLine],...
       'Parent',PlotAxes,'Tag','StabilityMarginMarker',...
       'Visible',Visible,'HandleVisibility','off','HitTest','off',...
       'Color',LC,'LineStyle','-');
    uistack(Hg(end),'bottom');
    Hg(end+1) = line(GmPlotP(n),GmPlotM(n),...
       'Parent',PlotAxes,'Tag','StabilityMarginMarker',...
       'Visible',Visible,'HandleVisibility','off',...
       'Marker','o','MarkerSize',6,'MarkerEdgeColor',CC,'MarkerFaceColor',CC,...
       'ButtonDownFcn','rguifcn(''plotoptbuttondown'',gcbf)',...
       'UserData',Udstr);
end

%---Don't render infinite margins and update status text if any exist
idx = isinf(Pm);
if any(idx)
   Status = InfWarning;
   Pm(idx) = [];
   Wcp(idx) = [];
end

%---Determine which margins are with range
InRange1 = Wcp>=Frequency(1);
InRange2 = Wcp<=Frequency(end);
InRange = InRange1 & InRange2;
WcpDisp = Wcp;
Wcp(InRange1==0) = Frequency(1);
Wcp(InRange2==0) = Frequency(end);

%---180deg value in current units
PmPlot = interp1(Frequency,PhaseData,Wcp);
if strncmpi(RespObj.PhaseUnits,'d',1)
   PmLine = 360*round((PmPlot(:)-Pm(:)-180)/360) + 180;
else
   PmLine = 2*pi*round((PmPlot(:)-Pm(:)-pi)/(2*pi)) + pi;
end

%---180deg line(s)
PmLineUnique = unique(PmLine);
for n=1:length(PmLineUnique)
   Hp(end+1) = line([PmLineUnique(n);PmLineUnique(n)],[NaN;NaN],...
      'Parent',PlotAxes,'Tag','StabilityMarginMarker',...
      'Visible',Visible,'HandleVisibility','off','HitTest','off',...
      'Color',LC,'LineStyle','-.','UserData',180);
end
uistack(Hp(:),'bottom');

%---Render
for n=1:length(Pm)
   %---Display string
    Udstr = {SystemStr;...
       sprintf('Phase margin (%s): %0.3g',RespObj.PhaseUnits,Pm(n));...
       sprintf('At frequency (%s): %0.3g',RespObj.FrequencyUnits,WcpDisp(n));...
       sprintf('Closed-loop stable? %s',Stable)};
   %---Add delay margin info (if displaying all stability margins)
    if All
       Udstr = {Udstr{1};Udstr{2};...
                sprintf('Delay margin (sec): %0.3g',Dm(n));...
                Udstr{3};Udstr{4}};
    end
   %---Render
    Hp(end+1) = line([Pm(n)+PmLine(n);PmLine(n)],[GmLine;GmLine],...
       'Parent',PlotAxes,'Tag','StabilityMarginMarker',...
       'Visible',Visible,'HandleVisibility','off','HitTest','off',...
       'Color',LC,'LineStyle','-');
    uistack(Hp(end),'bottom');
    Hp(end+1) = line(Pm(n)+PmLine(n),GmLine,...
       'Parent',PlotAxes,'Tag','StabilityMarginMarker',...
       'Visible',Visible,'HandleVisibility','off',...
       'Marker','o','MarkerSize',6,'MarkerEdgeColor',CC,'MarkerFaceColor',CC,...
       'ButtonDownFcn','rguifcn(''plotoptbuttondown'',gcbf)',...
       'UserData',Udstr);
end

%---We may have 1 extra point for delay margin (AllMargin display only)
if ~isempty(DmR)
   xp = unitconv(180,'deg',RespObj.PhaseUnits)*(DmR<0);
   if strncmpi(RespObj.PhaseUnits,'d',1)
      Xpos = 360*round((PhaseData(end)-xp)/360)+xp;
   else
      Xpos = 2*pi*round((PhaseData(end)-xp)/(2*pi))+xp;
   end
   %---Display string
    Udstr = {SystemStr;...
       sprintf('Delay margin (sec): %0.3g',Dm(end));...
       sprintf('At frequency (%s): %0.3g',RespObj.FrequencyUnits,Wcd(end));...
       sprintf('Closed-loop stable? %s',Stable)};
   %---Render
    Hp(end+1) = line(Xpos,unitconv(abs(real(DmR)),'abs',RespObj.MagnitudeUnits),...
       'Parent',PlotAxes,'Tag','StabilityMarginMarker',...
       'Visible',Visible,'HandleVisibility','off',...
       'Marker','o','MarkerSize',6,'MarkerEdgeColor',CC,'MarkerFaceColor',CC,...
       'ButtonDownFcn','rguifcn(''plotoptbuttondown'',gcbf)',...
       'UserData',Udstr);
end

%---Return line handles
RH = [RH ; Hg(:) ; Hp(:)];


%%%%%%%%%%%%%%%%%%%%%%%
% localConnectorColor %
%%%%%%%%%%%%%%%%%%%%%%%
function C = localConnectorColor(Ax)
%---Determine good color for connector lines in axes Ax
 AC = get(Ax,'Color');
 if isstr(AC), AC = get(get(Ax,'Parent'),'Color'); end
 if sum(AC)>1.5
    C = [0.7 0.7 0.7];
 else
    C = [0.7 0.7 0.7];
 end
