function [mgn,z] = yinyang (z, opts, output_mgn)
%YINYANG  Give the signed margin of the Yin-Yang function.
%
%   Y = YINYANG(X, [ratio R orientation]) gives the output (1/-1) and
%   MGN = YINYANG(X, [ratio R], true) gives the minimal L2 distance of
%   each point in X to the boundaries. Outside of the normal Yin-Yang,
%   the boundary is the y-axis (for orientation 0).
%   X: each line is a point
%   ratio: the small disk (eye) radius vs. the big disk radius
%   R: the big disk radius
%
%   YINYANG('plot', [...]) plots the Yin-Yang symbol.

if nargin < 3, output_mgn = false; end
if nargin < 2, opts = []; end
opts = options([0.2 1 0], opts);
r = opts(1); R = opts(2); ori = opts(3);
assert(r < 0.5);
r = r * R; % radius of the eyes

if isstr(z) && strcmp(z, 'plot')
    gray = .4; % users can specify the "black" background
    if nargin >= 3, gray = output_mgn; end
    plot_yinyang(r, R, ori, gray);
    return;
end

if length(z) == 1, %% Generate random inputs
    assert(z == round(z));
    tz = 1.1 * (rand(2*z,2)*2-1);
    i = find(sum(tz.^2,2) < 1.1^2);
    assert(length(i) >= z);
    z = tz(i(1:z),:) * R;
    clear tz i
end

x = z(:,1); y = z(:,2);
if ori < 0, x = -x; ori = -ori; end
for i = 1:mod(ori,4)
    t = -x; x = y; y = t;
end

R2 = R / 2;
d1 = sqrt((x+R2).^2 + y.^2);
d2 = sqrt((x-R2).^2 + y.^2);
rd1 = r - d1;
d2r = d2 - r;
d1R2 = d1 - R2;
R2d2 = R2 - d2;

mgn = repmat(nan, length(x), 1);

i = (rd1 >= 0);                            % d1 <= r
mgn(i) = rd1(i);
i = (d2r <= 0);                            % d2 <= r
mgn(i) = d2r(i);

i = (d2r > 0) & (R2d2 >= 0) & (y <= 0);    % r < d2 & d2 <= R2 & y <= 0
mgn(i) = min(d2r(i), R2d2(i));
i = (rd1 < 0) & (d1R2 <= 0) & (y >= 0);    % r < d1 & d1 <= R2 & y >= 0
mgn(i) = max(d1R2(i), rd1(i));

c1 = -sqrt((x+R).^2 + y.^2);
c2 = sqrt((x-R).^2 + y.^2);
i = (abs(x) >= R);
c1(i) = y(i); c2(i) = y(i);

i = (d2r > 0) & (d1R2 > 0) & (y >= 0);     % r < d2 & R2 < d1 & y >= 0
mgn(i) = min(min(d2r(i), d1R2(i)), c2(i));
i = (rd1 < 0) & (R2d2 < 0) & (y <= 0);     % r < d1 & R2 < d2 & y <= 0
mgn(i) = max(max(rd1(i), R2d2(i)), c1(i));

assert(all(~isnan(mgn)));
if ~output_mgn
    mgn = sign(mgn);
end


function plot_yinyang (r, R, ori, gray)
hold on; axis equal; axis off;
gray = gray * [1 1 1];

t = [0:359 0]/180*pi;
ct = cos(t); st = sin(t);
ct2 = ct(1:(end-1)/2); st2 = st(1:(end-1)/2);

R2 = R / 2;
px = [r*ct+R2 r*ct-R2 R2-R2*ct2  R*ct2 -R2-R2*ct2 0];
py = [r*st    r*st      -R2*st2 -R*st2     R2*st2 0];
sep = length(ct);

if ori < 0, px = -px; ori = -ori; end
for i = 1:mod(ori,4)
    t = px; px = -py; py = t;
end

h = patch(px(1:sep), py(1:sep), gray);
set(h, 'EdgeColor', gray, 'LineWidth', 0.01);
h = patch(px(sep+1:end), py(sep+1:end), gray);
set(h, 'EdgeColor', gray, 'LineWidth', 0.01);
plot(R*ct, R*st, 'Color', gray);
