Circle with Alternating coloured segments

1 view (last 30 days)
David
David on 5 Dec 2022
Edited: DGM on 6 Dec 2022
I wanted to reverse engineer this colour wheel code so that I can specify what colour each segment has: segment 1 - green, segment 2-13, red and segment 14-26, black (like a roulette wheel). I'm a little stuck on how to approach this (I've experimented with a simpler code to see if I could use cartesian only but can't see a way to merge them):
% Set parameters (these could be arguments to a function)
rInner = 80; % inner radius of the colour ring
rOuter = 200; % outer radius of the colour ring
ncols = 27; % number of colour segments
% Get polar coordinates of each point in the domain
[x, y] = meshgrid(-rOuter:rOuter);
[theta, rho] = cart2pol(x, y);
% Set up colour wheel in hsv space
hue = (theta + pi) / (2 * pi); % hue into range (0, 1]
hue = ceil(hue * ncols) / ncols; % quantise hue
saturation = ones(size(hue)); % full saturation
brightness = double(rho >= rInner & rho <= rOuter); % black outside ring
% Convert to rgb space for display
rgb = hsv2rgb(cat(3, hue, saturation, brightness));
% Check result
imshow(rgb);
My experiment code:
figure
N = 37;
a = linspace(0, 2*pi, N*10);
r = 1;
x = r*cos(a);
y = r*sin(a);
plot(x, y)
hold on
plot([zeros(1,N); x(1:10:end)], [zeros(1,N); y(1:10:end)])
axis equal
axis off
Additionally I was wondering what tweaks I would need to make so that I can perform a matrix transformation to it (For a rotation animation):
function rShape = rotateShape(shape, a)
%Rotates shape by angle a
%Matrix operation to rotate shape
rShape = [cos(a) -sin(a); sin(a) cos(a)] * shape;
end

Accepted Answer

DGM
DGM on 6 Dec 2022
Here's one example. I'm sure this can be simplified. It's flexible enough that you can adapt it for different standard wheel configurations.
% Set parameters (these could be arguments to a function)
rInner = 150; % inner radius of the colour ring
rOuter = 200; % outer radius of the colour ring
% this is the clockwise sequence for a european pattern single-green wheel
slotnums = [0 32 15 19 4 21 2 25 17 34 6 27 13 36 11 30 8 23 10 5 24 16 33 1 20 14 31 9 22 18 29 7 28 12 35 3 26];
slotidx = [1 3 2 3 2 3 2 3 2 3 2 3 2 3 2 3 2 3 2 3 2 3 2 3 2 3 2 3 2 3 2 3 2 3 2 3 2];
CT = [0 0.5 0; 0.1 0.1 0.1; 0.5 0 0]; % make up some colors
nslots = numel(slotnums); % number of colour segments
offset = 45; % specify angle offset (degrees)
% Get polar coordinates of each point in the domain
[x, y] = meshgrid(-rOuter:rOuter);
[theta, rho] = cart2pol(x, y);
% generate segments
outpict = mod(rad2deg(theta)+offset,360)/360; % normalize
outpict = ceil(outpict * nslots); % quantise
outpict = ind2rgb(outpict,CT(slotidx,:));
% mask off annular region
mk = double(rho >= rInner & rho <= rOuter);
outpict(repmat(~mk,[1 1 3])) = 0;
% show result
imshow(outpict); hold on
% add numbers
textrad = rInner + 0.65*(rOuter-rInner); % or pick some radius
th0 = 360/nslots;
th = linspace(0,360-th0,nslots) - offset + th0/2;
cen = size(outpict(:,:,1))/2;
for k = 1:numel(th)
x = textrad*cosd(th(k)) + cen(2);
y = textrad*sind(th(k)) + cen(1);
ht = text(x,y,sprintf('%d',slotnums(k)));
ht.Color = [1 1 1];
ht.FontSize = 10;
ht.FontWeight = 'bold';
ht.HorizontalAlignment = 'center';
ht.Rotation = 270-th(k);
end
  8 Comments
David
David on 6 Dec 2022
Edited: David on 6 Dec 2022
Thank you so much for the explanation!
Found a weird behaviour. When using the imagesc line:
imagesc(-rOuter: rOuter, -rOuter: rOuter, segm);
I can scale the axis but not the image (I can't get it to create a zoom out effect), is that because the wheel has its own indepedent coordinate plane when I defined it as
[x, y] = meshgrid(-rOuter:rOuter);
The numbers seem to be affected by the imagesc line (they appear to be smaller as the axis covers a greater range, but the wheel remains the same in scale)
DGM
DGM on 6 Dec 2022
Edited: DGM on 6 Dec 2022
I'm not sure exactly how the text 'fontsize' relates to axes units, but otherwise if you want to be able to adjust the zoom level, you might do that by manipulating xlim and ylim. If xlim and ylim are equal to the limits given in the call to imagesc(), then the image will always fill the axes regardless of its scale.
If you don't necessarily want to adjust the zoom, but just want more padding around the wheel, then you can just make the image bigger to start with.
% ...
maxr = 300; % the maximum image radius (independent of the wheel)
% ...
[x, y] = meshgrid(-maxr:maxr);
% ...
imagesc(-maxr:maxr, -maxr:maxr, segm);
% ...

Sign in to comment.

More Answers (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!