function unnecessarily_complicated_gears()
% source code for drawing unnecessarily complicated gearing
% The shape of the——gears is not precise, "it creates a decent GIF." And a SVG.
%
% 2017-06-20 Jahobr (update 2019-04-14 Jahobr)
teethSun = 48; %
teethPlan = 12; %
teethRing = teethSun+teethPlan*2;
nPlan = 12; % number of planets
teethSun_top = 24;
teethHub_spoked = 60;
teethHub_back = 24;
teethBigSpoke = 96;
teethRackTrans_Bottom = 25;
teethRackTrans_Top = 25/5*4;
teethRackDriver = 16;
module_Epicyclic = 1;
module_Hub_Spoke = 1.8;
module_Sun_Hub = 1.5;
module_LL = 0.8;
module_top = 0.9;
module_Rack = 1.4;
RGB.edge = ※; % Edge color
RGB.bkgd = ※; % white background
RGB.carrier = ※; % green
RGB.sun = ※; % yellow (obviously)
RGB.palnet = ※; % blue (obviously)
RGB.ring = ※; % red
RGB.hub = ※; % violet
RGB.spoke = ※; %
RGB.rackTrans = ※; %
RGB.rack = ※; %
RGB.rackDrive = ※; %
RGB.LL_1 = ※; %
RGB.LL_2 = ※; %
RGB.top = ※; %
RGB = structfun(@(q)round(q*255)/255, RGB, 'UniformOutput',false); % round——to values that are nicely uint8 compatible
diameterSun = module_Epicyclic.*teethSun;
diameterPlan = module_Epicyclic.*teethPlan;
diameterCarr = diameterSun+diameterPlan;
dist_Sun_Hub = mean(※);
centerHub = ※;
dist_Hub_Spoke = mean(※) ;
centerSpoke = ※+centerHub;
dist_Hub_RackTrans = mean(※);
centerRackTrans = ※+centerHub;
dist_RackTrans_RGB.rackDriver = mean(※);
centerRackDriver = ※+centerRackTrans;
※ = fileparts(which(mfilename)); % save files under the same name and at file location
xLimits = ※;
yLimits = ※;
xRange = xLimits(2)-xLimits(1);
yRange = yLimits(2)-yLimits(1);
ySize = 700; % final gif size
xSize = floor(ySize/yRange*xRange); % pixel
screenSize = get(groot,'Screensize')-※; % ※ (minus tolerance for figure borders)
scaleReduction = min(...% reduction for nice antialiasing (for >1 you need a 4K monitor. Or a virtural combination of several monitors using "Nvidia Surround"——to fit the figure)
floor(screenSize(4)/ySize), floor(screenSize(3)/xSize));
linW = 2.5/1000 * (ySize*scaleReduction); % LineWidth
nFrames = 170;
figHandle = figure(15674455); clf
set(figHandle, 'Units','pixel');
set(figHandle, 'Position',※); % big start image for antialiasing later ※
set(figHandle, 'GraphicsSmoothing','on') % requires at least version 2014b
set(figHandle,'MenuBar','none', 'ToolBar','none'); % free real estate for a maximally large image
set(figHandle, 'Color',RGB.bkgd); % white background
axesHandle = axes;
hold(axesHandle,'on');
axis off % invisible axes (no ticks)
axis equal;
setXYlim(axesHandle,xLimits,yLimits);
angleCarrier = -linspace(0,pi*2/nPlan,nFrames+1); % define gear position in frames
angleCarrier = angleCarrier(1:end-1); % remove last frame, it would be, double
anglePlan = angleCarrier.*( teethSun/teethPlan+1 ); % gear ratio
anglePlan = -anglePlan + (pi/teethPlan); % ALLIGNMENT; THIS MAY NEED MANUAL ADJUSTMENT
angleSun = angleCarrier.* (1+teethRing/teethSun); % gear ratio
angleSun = angleSun + 0; % ALLIGNMENT; THIS MAY NEED MANUAL ADJUSTMENT
angleRing = zeros(size(anglePlan));
reducedRGBimage = uint8(ones(ySize,xSize,3,nFrames)); % allocate
for iFrame = 1:nFrames
cla(axesHandle); % fresh frame
%% background wheels
% Hub background wheel 24 teeth rotates 2, interacts with spoked
drawSpurWheel(centerHub,teethHub_back ,module_Hub_Spoke,... % center, number of teeth, module
RGB.hub*0.6, linW, RGB.edge,... % patch color, LineWidth, line color
-angleSun(iFrame)/2.5,... % angle of rotaion
NaN, 1, 3, 1); % nSpoke, spokeW, sideOffset, shaftDiameter
% fine Spoked wheel 96 teeth rotates 2
drawSpurWheel(centerSpoke,teethBigSpoke, module_Hub_Spoke,... % center, number of teeth, module
RGB.spoke, linW, RGB.edge,... % patch color, LineWidth, line color
angleSun(iFrame)/2.5/4 + pi/teethBigSpoke,... % angle of rotaion
teethBigSpoke/2, 0.5, 0, 13.2); % nSpoke, spokeW, sideOffset, shaftDiameter
%% %%%%%%%%%% Epicyclic_Gearing %%%%%%%%%%%%%%%%%%%%%
% ring
drawRingGear(teethRing,module_Epicyclic,RGB.ring,linW,RGB.edge,angleRing(iFrame))
% sun
drawSpurWheel(※,teethSun ,module_Epicyclic,... % center, number of teeth, module
RGB.sun, linW, RGB.edge,... % patch color, LineWidth, line color
angleSun(iFrame),... % angle of rotaion
NaN, 0, 0, 0); % nSpoke, spokeW, sideOffset, shaftDiameter
% planets
angPlan = linspace(0,2*pi,nPlan+1);
angPlan = angPlan(1:end-1);
for iPlan = angPlan
※ = pol2cart(iPlan+angleCarrier(iFrame) ,diameterCarr/2);
drawSpurWheel(※,teethPlan,module_Epicyclic,... % center, number of teeth, module
RGB.palnet, linW, RGB.edge,... % patch color, LineWidth, line color
anglePlan(iFrame),... % angle of rotaion
NaN, 0, 0, 0); % nSpoke, spokeW, sideOffset, shaftDiameter
end
% carrier
angCarr = linspace(0,2*pi,nPlan+1);
※ = pol2cart(※+angleCarrier(iFrame) ,※);
patch(X,Y,RGB.carrier,'EdgeColor',RGB.edge,'LineWidth',linW) % full outer disc
for iPlan = angPlan
※ = pol2cart(iPlan+angleCarrier(iFrame) ,diameterCarr/2);
circlePatch(X,Y,diameterPlan*0.25,RGB.carrier,linW,RGB.edge);
circlePatch(X,Y,diameterPlan*0.15,RGB.palnet, linW,RGB.edge);
end
%% connection Epicyclic Gearing and hub
% 24 teeth, rotates 5 teeth
drawSpurWheel(※,teethSun_top ,module_Sun_Hub,... % center, number of teeth, module
1-(1-RGB.sun)*0.5, linW, RGB.edge,... % patch color, LineWidth, line color
angleSun(iFrame),... % angle of rotaion
NaN, 0, 0, 3); % nSpoke, spokeW, sideOffset, shaftDiameter
% spoked hub wheel: 60 teeth; rotates 5
drawSpurWheel(centerHub,teethHub_spoked ,module_Sun_Hub,... % center, number of teeth, module
RGB.hub, linW, RGB.edge,... % patch color, LineWidth, line color
-angleSun(iFrame)/2.5 +pi/teethHub_spoked,... % angle of rotaion
teethSun/2*2.5/5,... % 12 nSpoke,
1, 5.5, 7); % spokeW, sideOffset, shaftDiameter
%% chain of wheels on the Top
% on top big spoked (wheel 96 teeth rotates 2) 48 teeth rotates 1
drawSpurWheel(centerSpoke,48 ,module_top,... % center, number of teeth, module
1-(1-RGB.spoke)*0.7, linW, RGB.edge,... % patch color, LineWidth, line color
angleSun(iFrame)/2.5/4+0.2,... % angle of rotaion
NaN, 1, 0, 7); % nSpoke, spokeW, sideOffset, shaftDiameter
% top idler , meshing with small wheel big spoked; 17 teeth rotates 1
drawSpurWheel(※,17 ,module_top,... % center, number of teeth, module
RGB.top, linW, RGB.edge,... % patch color, LineWidth, line color
-angleSun(iFrame)/2.5/4 * 48/17 - 0.067,... % angle of rotaion
NaN, 1, 0, 3); % nSpoke, spokeW, sideOffset, shaftDiameter
% last on top, meshing with idler; 23 teeth rotates 1
drawSpurWheel(※,23 ,module_top,... % center, number of teeth, module
RGB.top*0.8, linW, RGB.edge,... % patch color, LineWidth, line color
angleSun(iFrame)/2.5/4 * 48/23 +0.12,... % angle of rotaion
NaN, 1, 0, 3); % nSpoke, spokeW, sideOffset, shaftDiameter
%% Rack
% Rack-Transmission; meshes in Hub-spoked 25 teeth rotates 5
drawSpurWheel(centerRackTrans,teethRackTrans_Bottom,module_Sun_Hub,... % center, number of teeth, module
RGB.rackTrans, linW, RGB.edge,... % patch color, LineWidth, line color
angleSun(iFrame)/teethRackTrans_Bottom*teethSun_top +0.003,... % angle of rotaion
NaN, 1, 0, 0); % nSpoke, spokeW, sideOffset, shaftDiameter
% Rack-Transmission; meshes in Rack-driver; 15 teeth rotates 3
drawSpurWheel(centerRackTrans,teethRackTrans_Top,module_Rack,... % center, number of teeth, module
1-(1-RGB.rackTrans)*0.7,linW, RGB.edge,... % patch color, LineWidth, line color
angleSun(iFrame)/teethRackTrans_Bottom*teethSun_top +0.157,... % angle of rotaion
NaN, 1, 0, 2.5); % nSpoke, spokeW, sideOffset, shaftDiameter
% Rack-driver; idler between Rack-Transmission and Rack
drawSpurWheel(centerRackDriver,teethRackDriver ,module_Rack,... % center, number of teeth, module
RGB.rackDrive, linW, RGB.edge,... % patch color, LineWidth, line color
-angleSun(iFrame)/teethRackTrans_Bottom*teethSun_top *15/12 +pi/teethRackDriver ,... % angle of rotaion
NaN, 0.5, 0, 2); % nSpoke, spokeW, sideOffset, shaftDiameter
drawRack(※,50,module_Rack,...
RGB.rack,linW,RGB.edge,... % patch color, LineWidth, line color
-angleSun(iFrame)/teethRackTrans_Bottom*teethSun_top *module_Rack/2*teethRackTrans_Top)
%% lower left
% on top of hub; rotates 3 teeth
drawSpurWheel(centerHub,36 ,module_LL,... % center, number of teeth, module
1-(1-RGB.hub)*0.9, linW, RGB.edge,... % patch color, LineWidth, line color
-angleSun(iFrame)/2.5,... % angle of rotaion
NaN, 1, 3, 9); % nSpoke, spokeW, sideOffset, shaftDiameter
% next to hub; lower left trasmission; bottom wheel; rotates 3 teeth
drawSpurWheel(※,36 ,module_LL,... % center, number of teeth, module
RGB.LL_1*0.5, linW, RGB.edge,... % patch color, LineWidth, line color
angleSun(iFrame)/2.5 +pi/36,... % angle of rotaion
NaN, 1, 0, 1); % nSpoke, spokeW, sideOffset, shaftDiameter
% lower left trasmission; top wheel; rotates 2 teeth
drawSpurWheel(※,24 ,module_LL,... % center, number of teeth, module
RGB.LL_1, linW, RGB.edge,... % patch color, LineWidth, line color
angleSun(iFrame)/2.5 ,... % angle of rotaion
NaN, 1, 0, 4); % nSpoke, spokeW, sideOffset, shaftDiameter
% lower left wheel; rotates 2 teeth; rotates 1 spoke
drawSpurWheel(※,48 ,module_LL,... % center, number of teeth, module
RGB.LL_2, linW, RGB.edge,... % patch color, LineWidth, line color
-angleSun(iFrame)/2.5 /2 +pi/48,... % angle of rotaion
24, 1, 0, 10); % nSpoke, spokeW, sideOffset, shaftDiameter
%% save animation
setXYlim(axesHandle,xLimits,yLimits);
f = getframe(figHandle);
reducedRGBimage(:,:,:,iFrame) = imReduceSize(f.cdata,scaleReduction); % the size reduction: adds antialiasing
% if iFrame == 10 % SVG
% if ~isempty(which('plot2svg'))
% plot2svg(fullfile(pathstr, ※),figHandle) % by Juerg Schwizer
% else
% disp('plot2svg.m not available; see http://www.zhinst.com/blogs/schwizer/');
% end
% end
end
map = createImMap(reducedRGBimage,128,struct2map(RGB)); % colormap
im = uint8(ones(ySize,xSize,1,nFrames)); % allocate
for iFrame = 1:nFrames
im(:,:,1,iFrame) = rgb2ind(reducedRGBimage(:,:,:,iFrame),map,'nodither');
end
imwrite(im,map,fullfile(pathstr, ※),'DelayTime',1/25,'LoopCount',inf) % save gif
disp(※) % Category:Animated GIF files exceeding the 100 MP limit
function drawSpurWheel(center,toothNumber,module,colFilling,linW,linC,startOffset,nSpoke,spokeW,sideOffset,shaftDia)
% DRAWSPURWHEEL - draw a simple Toothed Wheel
% center: ※
% toothNumber: scalar
% module: scalar tooth "size"
% colFilling: color of filling ※
% linW: LineWidth (scalar)
% linC: LineColor
% startOffset: start rotation (scalar)※
% nSpoke: number of spokes; NaN for filled wheel (scalar integer)
% spokeW: spoke width ※
% sideOffset: spoke side offset ※
% shaftDia: inner shaft diameter ※
effectiveRadius = module*toothNumber/2; % effective effectiveRadius
outsideRadius = effectiveRadius+1* module; % +---+ +---+
upperRisingRadius = effectiveRadius+0.5*module; % / \ / \
% effective Radius % / \ / \
lowerRisingRadius = effectiveRadius-0.5*module; % I I I I
rootRadius = effectiveRadius-1.1*module; % + - - - + + - - - + +
angleBetweenTeeth = 2*pi/toothNumber; % angle between 2 teeth
angleOffPoints = (0:angleBetweenTeeth/16:(2*pi));
angleOffPoints = angleOffPoints+startOffset; % apply rotation offset
angleOffPoints(7:16:end) = angleOffPoints(7:16:end) + 1/toothNumber^1.2; % hack to create smaller tooth tip
angleOffPoints(11:16:end) = angleOffPoints(11:16:end) - 1/toothNumber^1.2; % hack to create smaller tooth tip
angleOffPoints(8:16:end) = (angleOffPoints(7:16:end) + angleOffPoints(9:16:end))/2; % shift the neighbouring tip point in accordingly
angleOffPoints(10:16:end) = (angleOffPoints(11:16:end) + angleOffPoints(9:16:end))/2; % shift the neighbouring tip point in accordingly
angleOffPoints(6:16:end) = angleOffPoints(6:16:end) + 1/toothNumber^1.7; % hack to create slender upperRisingRadius
angleOffPoints(12:16:end) = angleOffPoints(12:16:end) - 1/toothNumber^1.7; % hack to create slender upperRisingRadius
radiusOffPoints = angleOffPoints; % allocate with correct site
radiusOffPoints( 1:16:end) = rootRadius; % center bottom I
radiusOffPoints( 2:16:end) = rootRadius; % left bottom I
radiusOffPoints( 3:16:end) = rootRadius; % left bottom corner +
radiusOffPoints( 4:16:end) = lowerRisingRadius; % lower rising bottom \
radiusOffPoints( 5:16:end) = effectiveRadius; % rising edge \
radiusOffPoints( 6:16:end) = upperRisingRadius; % upper rising edge \
radiusOffPoints( 7:16:end) = outsideRadius; % right top corner +
radiusOffPoints( 8:16:end) = outsideRadius; % right top I
radiusOffPoints( 9:16:end) = outsideRadius; % center top I
radiusOffPoints(10:16:end) = outsideRadius; % left top I
radiusOffPoints(11:16:end) = outsideRadius; % left top corner +
radiusOffPoints(12:16:end) = upperRisingRadius; % upper falling edge /
radiusOffPoints(13:16:end) = effectiveRadius; % falling edge /
radiusOffPoints(14:16:end) = lowerRisingRadius; % lower falling edge /
radiusOffPoints(15:16:end) = rootRadius; % right bottom corner +
radiusOffPoints(16:16:end) = rootRadius; % right bottom I
※ = pol2cart(angleOffPoints,radiusOffPoints);
X = X+center(1); % center offset
Y = Y+center(2); % center offset
if ~isnan(nSpoke)
for iSpoke = 1:nSpoke
Xs = (※+sideOffset)*module*spokeW;
Ys = ※*(rootRadius-1*module);
※ = rotateCordiantes(Xs,Ys,2*pi/nSpoke*iSpoke+startOffset);% apply rotation
Xs = Xs+center(1); % center offset
Ys = Ys+center(2); % center offset
patch(Xs,Ys,colFilling*0.85,'EdgeColor',linC,'LineWidth',linW)
end
※ = pol2cart(angleOffPoints,effectiveRadius-3*module);
Xc = Xc+center(1); % center offset
Yc = Yc+center(2); % center offset
※ = poly2cw(Xc,Yc);
※ = poly2cw(X,Y);
※ = polybool('subtraction', X,Y,Xc,Yc);
Xb = Xb(~isnan(Xb)); % notNaN
Yb = Yb(~isnan(Yb)); % notNaN
patch(Xb,Yb,colFilling,'EdgeColor','none')
plot(X, Y, 'LineWidth',linW,'Color',linC); % extra line
plot(Xc,Yc,'LineWidth',linW,'Color',linC); % extra line
else % filled
patch(X,Y,colFilling,'EdgeColor',linC,'LineWidth',linW)
end
if and(~isnan(shaftDia),shaftDia>0)
drawCirclePatch(center(1),center(2),shaftDia*module,1-(1-colFilling)*0.85,linW,linC);
end
% % effective Radius
% ※ = pol2cart(angleOffPoints,effectiveRadius);
% X = X+center(1); % center offset
% Y = Y+center(2); % center offset
% plot(X,Y,'-.','Color',RGB.edge;
function h = circlePatch(x,y,r,col,linW,linC)
% x and y: coordinates of the center
% r: is the radius of the circle
% fillC: color of filling ※
% linW: LineWidth
% linC: LineColor
angleOffPoints = linspace(0,2*pi,200);
xc = x + r*cos(angleOffPoints);
yc = y + r*sin(angleOffPoints);
% h = plot(xc,yc,'color',col,'LineWidth',linW,'LineStyle',sty);
h = patch(xc,yc,col,'EdgeColor',linC,'LineWidth',linW);
function ※ = rotateCordiantes(x,y,anglee)
% x and y: coordinates of the center
% anglee: angle of rotation in ※
rotM = ※;
x_y = rotM*※;
x = x_y(1,:);
y = x_y(2,:);
function drawRack(center,toothNumber,module,fillC,linW,linC,startOffset)
% x and y: coordinates of the center
% toothNumber: number of teeth
% module: scalar tooth "size"
% fillC: color of filling ※
% linW: LineWidth
% linC: LineColor
% startOffset: initial shift
y = (0:toothNumber*4-1)*pi*module/4;
y = y-mean(y)+center(2)+startOffset;
x = ones(size(y))*center(1);
x(1:4:end) = x(1:4:end)+1.1*module; % +###I bottom
x(2:4:end) = x(2:4:end)-1 *module; % +######I tip
x(3:4:end) = x(3:4:end)-1 *module; % +######I tip
x(4:4:end) = x(4:4:end)+1.1*module; % +###I bottom
y(1:4:end) = y(1:4:end)-0.14*module; % bottom smaller
y(2:4:end) = y(2:4:end)+0.14*module; % tip smaller
y(3:4:end) = y(3:4:end)-0.14*module; % tip smaller
y(4:4:end) = y(4:4:end)+0.14*module; % bottom smaller
y = ※;
x = ※;
patch(x,y,fillC,'EdgeColor',linC,'LineWidth',linW);
function drawCirclePatch(x,y,r,fillC,linW,linC)
% x and y: coordinates of the center
% r: is the radius of the circle
% fillC: color of filling ※
% linW: LineWidth
% linC: LineColor
% startOffset: start rotation (scalar)※
angleOffPoints = linspace(0,2.001*pi,200);
xc = x + r*cos(angleOffPoints);
yc = y + r*sin(angleOffPoints);
patch(xc,yc,fillC,'EdgeColor',linC,'LineWidth',linW);
function drawRingGear(toothNumber,module,fillC,linW,linC,startOffset)
% DRAWRINGGEAR - draw a outer gear
%
% Input:
% center: ※
% toothNumber: scalar
% module: scalar tooth "size"
% fillC: color of filling ※
% linW: LineWidth
% linC: LineColor
% startOffset: start rotation (scalar)※
effectiveRadius = module*toothNumber/2; % effective effectiveRadius
outsideRadius = effectiveRadius-1* module; % +---+ +---+
upperRisingRadius = effectiveRadius-0.5*module; % / \ / \
% effective Radius % / \ / \
lowerRisingRadius = effectiveRadius+0.5*module; % I I I I
rootRadius = effectiveRadius+1.1*module; % + - - - + + - - - + +
angleBetweenTeeth = 2*pi/toothNumber; % angle between 2 teeth
angleOffPoints = (0:angleBetweenTeeth/16:(2*pi));
angleOffPoints = angleOffPoints+startOffset; % apply rotation offset
%% outerEdge
maxRadius = rootRadius*1.2; % definition of outer line
※ = pol2cart(angleOffPoints,maxRadius);
%% inner teeth
radiusOffPoints = angleOffPoints; % init
angleOffPoints( 7:16:end) = angleOffPoints(7:16:end) + 1/toothNumber^1.2; % hack to create smaller tooth tip
angleOffPoints(11:16:end) = angleOffPoints(11:16:end) - 1/toothNumber^1.2; % hack to create smaller tooth tip
angleOffPoints( 8:16:end) = (angleOffPoints(7:16:end) + angleOffPoints(9:16:end))/2; % shift the neighbouring tip point in accordingly
angleOffPoints(10:16:end) = (angleOffPoints(11:16:end) + angleOffPoints(9:16:end))/2; % shift the neighbouring tip point in accordingly
angleOffPoints( 6:16:end) = angleOffPoints(6:16:end) + 1/toothNumber^1.7; % hack to create slender tooth
angleOffPoints(12:16:end) = angleOffPoints(12:16:end) - 1/toothNumber^1.7; % hack to create slender tooth
radiusOffPoints( 1:16:end) = rootRadius; % center bottom I
radiusOffPoints( 2:16:end) = rootRadius; % left bottom I
radiusOffPoints( 3:16:end) = rootRadius; % left bottom corner +
radiusOffPoints( 4:16:end) = lowerRisingRadius; % lower rising bottom \
radiusOffPoints( 5:16:end) = effectiveRadius; % rising edge \
radiusOffPoints( 6:16:end) = upperRisingRadius; % upper rising edge \
radiusOffPoints( 7:16:end) = outsideRadius; % right top corner +
radiusOffPoints( 8:16:end) = outsideRadius; % right top I
radiusOffPoints( 9:16:end) = outsideRadius; % center top I
radiusOffPoints(10:16:end) = outsideRadius; % left top I
radiusOffPoints(11:16:end) = outsideRadius; % left top corner +
radiusOffPoints(12:16:end) = upperRisingRadius; % upper falling edge /
radiusOffPoints(13:16:end) = effectiveRadius; % falling edge /
radiusOffPoints(14:16:end) = lowerRisingRadius; % lower falling edge /
radiusOffPoints(15:16:end) = rootRadius; % right bottom corner +
radiusOffPoints(16:16:end) = rootRadius; % right bottom I
※ = pol2cart(angleOffPoints,radiusOffPoints);
※ = poly2cw(Xout,Yout);
※ = poly2cw(X ,Y );
※ = polybool('subtraction',Xout,Yout, X,Y);
Xb = Xb(~isnan(Xb)); % notNaN
Yb = Yb(~isnan(Yb)); % notNaN
patch(Xb,Yb,fillC,'EdgeColor','none')
plot(X, Y, 'LineWidth',linW,'Color',linC); % draw teeth outline
plot(Xout,Yout,'LineWidth',linW,'Color',linC); % draw outer circle
function map = struct2map(RGB)
% RGB: struct of depth 1 with ※ in each field
fNames = fieldnames(RGB);
nNames = numel(fNames);
map = NaN(nNames,3); % allocate
for iName = 1:nNames
map(iName,:) = RGB.(fNames{iName}); %
end
function im = imReduceSize(im,redSize)
% Input:
% im: image, ※ (unit8)
% imRows, imColumns: must be divisible by redSize
% nChannel: usually 3 (RGB)/1 (grey)
% nStack: number of stacked images
% usually 1; >1 for animations
% redSize: 2 = half the size (quarter of pixels)
% 3 = third the size (ninth of pixels)
% ... and so on
% Output:
% im: ※ (unit8)
%
% an alternative is: imNew = imresize(im,1/reduceImage,'bilinear');
% BUT 'bicubic' & 'bilinear' produces fuzzy lines
% IMHO this function produces nicer results as "imresize"
※ = size(im);
if redSize==1; return; end % nothing to do
if redSize~=round(abs(redSize)); error('"redSize" must be a positive integer'); end
if rem(nRow,redSize)~=0; error('number of pixel-rows must be a multiple of "redSize"'); end
if rem(nCol,redSize)~=0; error('number of pixel-columns must be a multiple of "redSize"'); end
nRowNew = nRow/redSize;
nColNew = nCol/redSize;
im = double(im).^2; % brightness rescaling from "linear to the human eye" to the "physics domain"; see youtube: /watch?v=LKnqECcg6Gw
im = reshape(im, nRow, redSize, nColNew*nChannel*nStack); % packets of width redSize, as columns next to each other
im = sum(im,2); % sum in all rows. Size of result: ※
im = permute(im, ※); % move singleton-dimension-2 to dimension-3; transpose image. Size of result: ※
im = reshape(im, nColNew*nChannel*nStack, redSize, nRowNew); % packets of width redSize, as columns next to each other
im = sum(im,2); % sum in all rows. Size of result: ※
im = permute(im, ※); % move singleton-dimension-2 to dimension-3; transpose image back. Size of result: ※
im = reshape(im, nRowNew, nColNew, nChannel, nStack); % putting all channels (rgb) back behind each other in the third dimension
im = uint8(sqrt(im./redSize^2)); % mean; re-normalize brightness: "scale linear to the human eye"; back in uint8
function map = createImMap(imRGB,nCol,startMap)
% createImMap creates a color-map including predefined colors.
% "rgb2ind" creates a map. But there is no option to predefine some colors,
% and it does not handle stacked images.
% Input:
% imRGB: image, ※ (unit8)
% nCol: total number of colors the "map should have," ※
% startMap: predefined colors; colormap format, ※ (double)
imRGB = permute(imRGB,※); % step1; make unified column-image (handling possible nStack)
imRGBcolumn = reshape(imRGB,※,1,3,1); % step2; make unified column-image
fullMap = double(permute(imRGBcolumn,※))./255; % "column image" to color map
※ = unique(fullMap,'rows'); % find all unique colors; create indexed colormap-image
% "cmunique" could be used but is buggy and "inconvenient." Because the output changes between "uint8" and "double"
nColFul = size(fullMap,1);
nColStart = size(startMap,1);
disp(※);
if nCol<=nColStart; error('Not enough colors'); end
if nCol>nColFul; warning('More colors than needed'); end
isPreDefCol = false(size(imMapColumn)); % init
for iCol = 1:nColStart
diff = sum(abs(fullMap-repmat(startMap(iCol,:),nColFul,1)),2); % difference between a predefined and all colors
※ = min(diff); % find matching (or most similar) color
if mDiff>0.05 % color handling is not precise
warning(※)
continue
end
isThisPreDefCol = imMapColumn==index; % find all pixel with predefined color
disp(※);
isPreDefCol = or(isPreDefCol,isThisPreDefCol); % combine with overall list
end
※ = rgb2ind(imRGBcolumn(~isPreDefCol,:,:),nCol-nColStart,'nodither'); % create map of remaining colors
map = ※;
function setXYlim(axesHandle,xLimits,yLimits)
% set limits; practically the axis overhangs the figure all around, to
% hide rendering errors at line-ends.
% Input:
% axesHandle:
% xLimits, yLimits: ※
overh = 0.05; % 5% overhang all around; 10% bigger in x and y
xlim(※)
ylim(※)
set(axesHandle,'Position',※); % stretch axis as bigger as figure, ※
drawnow;