Loren on the Art of MATLAB

October 31st, 2008

Olympic Rings

Well, I am very late on this challenge. In August, Mike posted some code to reproduce the Olympic rings and mentioned that I might have a more clever way to create the same plot. Here's my attempt.

Contents

Create X and Y Values for the 5 Rings

First, I'll follow Mike's parameters and code to create the initial five rings.

N = 1000;
angle = linspace(pi/4,9*pi/4,N);

xb = cos(angle) * 0.9;
yb = sin(angle) * 0.9;

xy = cos(angle) * 0.9 + 1;
yy = sin(angle) * 0.9 - 1;

xk = cos(angle) * 0.9 + 2;
yk = sin(angle) * 0.9;

xg = cos(angle) * 0.9 + 3;
yg = sin(angle) * 0.9 - 1;

xr = cos(angle) * 0.9 + 4;
yr = sin(angle) * 0.9;

Mike's Rings

What Mike does next is to break rings into segments for plotting so the last ring plotted in any given location is the color that should be on top.

h1 = figure;
hold on
plot(xb(1:3*N/4),yb(1:3*N/4),'b','linewidth',5);
plot(xy(N/4:N),yy(N/4:N),'y','linewidth',5)

plot(xk(1:3*N/4),yk(1:3*N/4),'k','linewidth',5);
plot(xy(1:N/4),yy(1:N/4),'y','linewidth',5);
plot(xb(3*N/4:end),yb(3*N/4:end),'b','linewidth',5);

plot(xr(1:N/2),yr(1:N/2),'r','linewidth',5);
plot(xg(1:N),yg(1:N),'g','linewidth',5);

plot(xk(3*N/4:N),yk(3*N/4:N),'k','linewidth',5);
plot(xr(N/2:N),yr(N/2:N),'r','linewidth',5);

% make the axis pretty
axis equal
axis off
xlim([-1.2 5.2])
set(h1,'Color',[1 1 1])
hold off

My Solution

My "cleverness" is to offset the rings in the Z-plane.

First I noticed that all the top rings have an axis about which I can "tilt" them ever so slightly to get the most of the over/under behavior for the rings. Add small Z values to each ring.

thetab = -pi/4;
thetak = -pi/4;
thetar = -pi/4;

Now I create Z values for the rings in the upper rows by tilting them about the axes defined by the angles above (which happen to be identical).

zb = cos(angle + thetab) * 0.1;
zk = cos(angle + thetak) * 0.1;
zr = cos(angle + thetar) * 0.1;

Next I deal with the lower rings in a lazy way, introducing a discontinuity in Z. If I had more patience today, I could have come up with an undulation in Z that was more than a tilted plane or a step.

I find the angles where I need to depress the bottom rings relative to the top and set appropriate Z values for these to be less than 0.

mask = angle >= 2*pi;
zg = zeros(size(xb));
zy = zeros(size(xb));
zg(mask) = -0.1;
zy(mask) = -0.1;

Loren's Rings

Here's my rendition of the rings. My plot commands are a bit less complicated than Mike's. I do the work earlier by setting Z values. Also, because of my laziness, if you were to rotate my version of rings in 3-D, you'd see the bottom two aren't really rings, but have discontinuities.

h2 = figure;
hold on
plot3(xb,yb,zb,'b.','markersize',10);
plot3(xy,yy,zy,'y.','markersize',10);
plot3(xk,yk,zk,'k.','markersize',10);
plot3(xg,yg,zg,'g.','markersize',10);
plot3(xr,yr,zr,'r.','markersize',10);
% make the axis pretty
axis equal
axis off
xlim([-1.2 5.2])
set(h2,'Color',[1 1 1])
hold off

Any Other Methods?

Mike and I show 2 methods to generate interlocking rings. Do you have any other ideas for doing this? Let me know here.


Get the MATLAB code

Published with MATLAB® 7.7

7 Responses to “Olympic Rings”

  1. Mike replied on :

    That’s great. I’m so used to thinking in 2-dimensions with my plots.

  2. mark replied on :

    If you want to do it as an image versus a plot then you can utilize convolution since the rings are identical. Admittedly the output doesn’t look as nice as above but I think it is a nice demonstration of the conv2 function…maybe.

    % first create a ‘ring’

    x=sin(2*pi*(1/100)*(0:99));
    y=cos(2*pi*(1/100)*(0:99));
    c=zeros(32,32);
    for i=1:100
    c(ceil(15*x(i))+16,ceil(15*y(i))+16)=1;
    end

    % then create your canvas
    A=zeros(128,128);

    % set ring spacing
    n=36;

    % convolving this set of impulses with
    % the ring will make the final output array
    % the different values will change the colors
    A(64,((0:2)*n)+20)=[1 3 5];
    A(64+15,([1/2 3/2]*n)+20)=[2 4];

    % use this to test the overlaps
    D(64,((0:2)*n)+20)=[1 1 1];
    D(64+15,([1/2 3/2]*n)+20)=[1 1];

    w=conv2(D,c,’same’);

    % find where the rings overlap
    [s,t]=find(w==2);

    f=[2 2 1 2 3 4 4 3 4 5];

    % create the final output array
    r=conv2(A,c,’same’);

    % replace with the ‘right values from left to right
    for ii=1:10
    r(s(ii),t(ii))=f(ii);
    end

    % set the color map to a white background
    % and five colors
    map=[1 1 1 ; 0 0 1 ; 1 1 0 ; 0 0 0 ; 0 1 0 ; 1 0 0]

    % display
    imagesc(r)

    colormap(map);

  3. Loren replied on :

    Mark-

    Thanks so much for sharing an entirely different approach!

    –Loren

  4. Tom Elmer replied on :

    Next I deal with the lower rings in a lazy way, introducing a discontinuity in Z. If I had more patience today, I could have come up with an undulation in Z that was more than a tilted plane or a step.

    No need to add undulations, just alternate your axis (and I added an alternating offset) then increment the angles/offsets on each ring. (Of course they’re really ellipses in 3D but the 2D projection is circular. Actually, it looks kinda neat on Y-Z view.) (I wasn’t mathematically rigorous on what the coefficients should be for N rings, but I did try it out to 28 rings.)

    N = 1000;
    angle = linspace(pi/4,9*pi/4,N);

    c=’bykgr’;
    %c=’bykgrmcbykgrmcbykgrmcbykgrmc’;
    index = 1:length(c);
    UL=( ~mod(index,2) – mod(index,2) ); %negative if Upper ring, positive if Lower ring

    h2 = figure(‘color’,[1 1 1]);
    hold on
    for loop=1:length(c)
    z = cos(angle + UL(loop)*pi/4) * … %alternating axes
    (length(c)-loop)*0.1*-UL(loop) + … %alternating angles
    .05*(length(c)-loop)*-UL(loop); %alternating depth offsets
    x = cos(angle) * 0.9 + (loop-1);
    y = sin(angle) * 0.9 – ~mod(loop,2);
    plot3(x,y,z,[c(loop) '.'],’markersize’,10);
    end
    axis equal off
    hold off

  5. Loren replied on :

    Tom-

    Thanks for an interesting and elegant solution!

    –Loren

  6. Hung Dang replied on :

    I fix Loren’s code a little bit to be able to reuse x and y and with a shorter plot command ;)

    %% Init parameters
    R = 0.9;
    scale = 1.1;
    N = 100;
    thickness = 10;
    angle = linspace(0,2*pi,N);

    %% Plot the rings
    y = R * sin(angle);
    x = R * cos(angle);
    plot(x,y,’b',x + scale * R,y – scale * R,’k',x + 2 * scale * R,y,’r',…
    x + 3 * scale * R, y – scale * R,’g',x + 4 * scale * R,y,’k',…
    ‘LineWidth’,thickness);

    %% Make axis look better
    axis off;
    set(gca,’XLim’,[-1.2 5.2]);
    set(gcf,’Color’,[1 1 1]);

  7. Tom Elmer replied on :

    I fix Loren’s code a little bit to be able to reuse x and y and with a shorter plot command ;)

    You missed the important part of the exercise in that the rings have to be interlocking :D


MathWorks
Loren Shure works on design of the MATLAB language at MathWorks. She writes here about once a week on MATLAB programming and related topics.

These postings are the author's and don't necessarily represent the opinions of MathWorks.