File:LissajousCurvesWithGears a1 b2 p00 p025 p05.gif

From Wikimedia Commons, the free media repository
Jump to navigation Jump to search

LissajousCurvesWithGears_a1_b2_p00_p025_p05.gif(527 × 527 pixels, file size: 7.77 MB, MIME type: image/gif, looped, 360 frames, 14 s)

Captions

Captions

Add a one-line explanation of what this file represents

Summary[edit]

Description
English: Lissajous curve crafted with gears. The figures shape is determined by the gear ratio between the lower left and the upper right wheel. The idler-wheel just transmits the movement and changes the direction of rotation. The gray markings on the upper right wheel show options of different phase shifts between 0 and π in steps of 1/8 of π.
Deutsch: Lissajous-Figur erstellt mit Zahnrädern. Die Figur ergibt sich aus dem Übersetzungsverhältnis zwischen dem unten linken und dem oberen rechten Rad. Das mittlere Rad überträgt nur die Bewegung; seine Zähnezahl spielt keine Rolle. Die grauen Markierungen am oberen rechten Rad zeigen mögliche Varianten des Phasenversatzes, von 0 bis π in Schritten von 1/8 π.
Date
Source Own work
Author Jahobr
Other versions
GIF development
InfoField
 
This diagram was created with MATLAB by Jahobr.
Source code
InfoField

MATLAB code

function [] = LissajousCurvesWithGears()
% Source code for drawing gears that produce lissajous curves.
% The shape of the gears is not precise, it creates a decent GIF and a SVG.
%
% 2017-05-01 Jahobr

module = 1; % gear size
[pathstr,fname] = fileparts(which(mfilename)); % save files under the same name and at file location

RGB.black      = [0   0   0  ];
RGB.white      = [1   1   1  ];
RGB.cyan       = [0   0.6 0.7]; % for phase shift 0.125
RGB.green      = [0   0.7 0  ]; % for phase shift 0.25
RGB.blue       = [0   0   1  ]; % for phase shift 0.5
RGB.red        = [1   0   0  ]; % for phase shift 0.0
RGB.violet     = [0.6 0.2 0.8]; % for horizontal line
RGB.brightGrey = [0.8 0.8 0.8]; % upper two Idler & "LeftRight gear"
RGB.grey       = [0.5 0.5 0.5]; % lower left "UpDown gear"

RGB.paleCyan   = 1-(1-RGB.cyan)  *0.85; % dotted line
RGB.paleGreen  = 1-(1-RGB.green) *0.85; % dotted line 
RGB.paleBlue   = 1-(1-RGB.blue)  *0.85; % dotted line 
RGB.paleRed    = 1-(1-RGB.red)   *0.85; % dotted line 
RGB.paleViolet = 1-(1-RGB.violet)*0.85; % dotted line 

RGB.violetGreyMix1 = sqrt(mean([RGB.paleViolet.^2;RGB.grey.^2;      RGB.grey.^2],1)); % experience shows that matlab does not create...
RGB.violetGreyMix2 = sqrt(mean([RGB.paleViolet.^2;RGB.paleViolet.^2;RGB.grey.^2],1)); %...nice mix colors in this combination; enforced

RGB = structfun(@(q)round(q*255)/255, RGB, 'UniformOutput',false); % round to values that are nicely uint8 compatible

versionList ={};
versionList{end+1} = 'a1_b1_p00';
versionList{end+1} = 'a1_b1_p025';
versionList{end+1} = 'a1_b1_p05';
versionList{end+1} = 'a1_b1_p00_p025_p05';
versionList{end+1} = 'a1_b2_p00';
versionList{end+1} = 'a1_b2_p025';
versionList{end+1} = 'a1_b2_p05';
versionList{end+1} = 'a1_b2_p00_p025_p05';
versionList{end+1} = 'a1_b3_p00';
versionList{end+1} = 'a1_b3_p025';
versionList{end+1} = 'a1_b3_p05';
versionList{end+1} = 'a1_b3_p00_p025_p05';
versionList{end+1} = 'a1_b4_p00';
versionList{end+1} = 'a1_b4_p025';
versionList{end+1} = 'a1_b4_p05';
versionList{end+1} = 'a1_b4_p00_p025_p05';
versionList{end+1} = 'a2_b3_p00';
versionList{end+1} = 'a2_b3_p0125';
versionList{end+1} = 'a2_b3_p025';
versionList{end+1} = 'a2_b3_p00_p0125_p025';
versionList{end+1} = 'a3_b4_p00';
versionList{end+1} = 'a3_b4_p025';
versionList{end+1} = 'a3_b4_p05';
versionList{end+1} = 'a3_b4_p00_p025_p05';

for versionNr = 1:numel(versionList)
    curVers = versionList{versionNr};
    
    switch curVers(1:5)
        case 'a1_b1'
            a=1; b=1;
            teeth = [48*a/b 48 48]; % [leftBottom leftTop rightTop]
        case 'a1_b2'
            a=1; b=2;
            teeth = [48*a/b 48 48]; % [leftBottom leftTop rightTop]
        case 'a1_b3'
            a=1; b=3;
            teeth = [48*a/b 50 48]; % [leftBottom leftTop rightTop]
        case 'a1_b4'
            a=1; b=4;
            teeth = [48*a/b 50 48]; % [leftBottom leftTop rightTop]
        case 'a2_b3'
            a=2; b=3;
            teeth = [48*a/b 48 48]; % [leftBottom leftTop rightTop]
        case 'a3_b4'
            a=3; b=4;
            teeth = [48*a/b 48 48]; % [leftBottom leftTop rightTop]
        otherwise
            error('not defined')
    end
    ratio = a/b; 
    rotToRepetition = lcm(a,b)/a; % Least common multiple, to produce a closed curve
    nFrames = 180*rotToRepetition; % 180 frames per rotation
    MegaPixelTarget = 100*10^6; % Category:Animated GIF files exceeding the 100 MP limit
    xySize = floor(sqrt(MegaPixelTarget/nFrames)); %  gif size in pixel
    screenSize = get(groot,'Screensize')-[0 0 5 20]; % [1 1 width height] (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)/xySize), floor(screenSize(3)/xySize)); 
    if scaleReduction == 0;   error('"MegaPixelTarget" not possible; use smaller target or bigger monitor'); end % check
    
    diameter = module.*teeth;
    
    %      ---     ---
    %    /  2  \ /  3  \
    %   ( Idler X   LR  ) Left-Right-Wheel
    %    \     / \     /
    %     >---<    ---
    %    /  1  \
    %   (   UD  )   + 0/0 of coordinates
    %    \     /
    %      --- Up-Down-Wheel
    
    center_UD_wheel = [-diameter(3) 0]; % wheel for Up-Down movement
    center_LR_wheel = [0  diameter(3)]; % wheel for Left-Right movement
    [xout,yout] = circcirc(center_UD_wheel(1),center_UD_wheel(2),mean(diameter(1:2)),center_LR_wheel(1),center_LR_wheel(2),mean(diameter(2:3))); % Intersections
    [centerIdler(2),ind] = max(yout);
    centerIdler(1) = xout(ind);

    
    figPosition = [1 1 xySize*scaleReduction xySize*scaleReduction]; % big start image for antialiasing later [x y width height]
    figHandle = figure(15554461); clf
    axesHandle = axes; hold(axesHandle,'on')
    set(figHandle,'Units','pixel');
    set(figHandle,'MenuBar','none',  'ToolBar','none'); % free real estate for a maximally large image
    set(figHandle,'Position',figPosition); % big start image; reduction allows for subpixel LineWidth
    set(figHandle,'GraphicsSmoothing','on') % requires at least version 2014b
    set(figHandle,'Color',RGB.white); % white background
    drawnow
    if ~all(get(figHandle, 'Position')==figPosition)
        error('figure Position could not be set')
    end
    liSc = xySize*scaleReduction/1000; % LineWidth scale; LineWidth is absolut, a bigger images needs thicker lines to keep them in proportion

    xLimits = [-1.55  0.55]*diameter(3); % ADJUST
    yLimits = [-0.55  1.55]*diameter(3); % ADJUST
    set(axesHandle,'Position',[0 0 1 1]); % stretch axis as big as figure, [x y width height]
    xlim(xLimits); ylim(yLimits); % set axis limits
    axis off % invisible axes (no ticks)
    axis equal; drawnow;
    
    angles_UD_wheel = linspace(0, rotToRepetition *2*pi,nFrames+1); % angles for wheel responsible for Up-Down
    angles_UD_wheel = angles_UD_wheel(1:end-1); % remove last frame, it would be double
    nShift = find(angles_UD_wheel>pi/6,1,'first');
    angles_UD_wheel = circshift(angles_UD_wheel,nShift,2); % shift a view frames to get good visibility of all lines in frame 1
    
    idlerRatio  = teeth(1)/teeth(2);
    anglesIdler = angles_UD_wheel.*idlerRatio;
    angles_LR_wheel = angles_UD_wheel*ratio;
    
    switch curVers(1:5)
        case 'a1_b1'
            anglesIdlerToothAllign  = anglesIdler + (2*pi/teeth(2)) *0.5; % ALLIGNMENT; THIS MAY NEED MANUAL ADJUSTMENT
            angles_LR_wheelToothAllign = angles_LR_wheel +(2*pi/teeth(3)) *0;   % ALLIGNMENT; THIS MAY NEED MANUAL ADJUSTMENT
        case 'a1_b2'
            anglesIdlerToothAllign  = anglesIdler + (2*pi/teeth(2)) *-0.01; % ALLIGNMENT; THIS MAY NEED MANUAL ADJUSTMENT
            angles_LR_wheelToothAllign = angles_LR_wheel +(2*pi/teeth(3)) *0.36; % ALLIGNMENT; THIS MAY NEED MANUAL ADJUSTMENT
        case 'a1_b3'
            anglesIdlerToothAllign  = anglesIdler + (2*pi/teeth(2)) *0.43; % ALLIGNMENT; THIS MAY NEED MANUAL ADJUSTMENT
            angles_LR_wheelToothAllign = angles_LR_wheel +(2*pi/teeth(3)) *-0.21; % ALLIGNMENT; THIS MAY NEED MANUAL ADJUSTMENT
        case 'a1_b4'
            anglesIdlerToothAllign  = anglesIdler + (2*pi/teeth(2)) *-0.34; % ALLIGNMENT; THIS MAY NEED MANUAL ADJUSTMENT
            angles_LR_wheelToothAllign = angles_LR_wheel +(2*pi/teeth(3)) *-0.29; % ALLIGNMENT; THIS MAY NEED MANUAL ADJUSTMENT
        case 'a2_b3'
            anglesIdlerToothAllign  = anglesIdler + (2*pi/teeth(2)) *-0.29; % ALLIGNMENT; THIS MAY NEED MANUAL ADJUSTMENT
            angles_LR_wheelToothAllign = angles_LR_wheel +(2*pi/teeth(3)) *-0.23; % ALLIGNMENT; THIS MAY NEED MANUAL ADJUSTMENT
        case 'a3_b4'
            anglesIdlerToothAllign  = anglesIdler + (2*pi/teeth(2)) *0.62; % ALLIGNMENT; THIS MAY NEED MANUAL ADJUSTMENT
            angles_LR_wheelToothAllign = angles_LR_wheel +(2*pi/teeth(3)) *0.03; % ALLIGNMENT; THIS MAY NEED MANUAL ADJUSTMENT
        otherwise
            error('not defined')
    end
    
    curvePoints = linspace(0,2*pi,500);
    yCurvePoints00   = NaN(size(curvePoints)); % defaults
    yCurvePoints0125 = NaN(size(curvePoints)); % defaults
    yCurvePoints025  = NaN(size(curvePoints)); % defaults
    yCurvePoints05   = NaN(size(curvePoints)); % defaults
    
    if contains(curVers,'p00')   % Phase shift 0
        yCurvePoints00   = sin(b*curvePoints     )*0.9*diameter(3)/2; % Lissajous curve
    end
    if contains(curVers,'p0125') % Phase shift 1/8*pi = 0.125*pi
        yCurvePoints0125 = sin(b*curvePoints-pi/8)*0.9*diameter(3)/2; % Lissajous curve
    end
    if contains(curVers,'p025')  % Phase shift 1/4*pi = 0.25*pi
        yCurvePoints025  = sin(b*curvePoints-pi/4)*0.9*diameter(3)/2; % Lissajous curve
    end
    if contains(curVers,'p05')   % Phase shift 1/2*pi = 0.5*pi
        yCurvePoints05   = sin(b*curvePoints-pi/2)*0.9*diameter(3)/2; % Lissajous curve
    end
    
    
    xCurvePoints  = sin(a*    curvePoints     )*0.9*diameter(3)/2; % Lissajous curve
    
    x_y_Crank = [-module*2 -module*2 0.9*diameter(3)/2+module 0.9*diameter(3)/2+module;...
        -module*2  module*2           module                  -module];
    
    anglesPSmakerXw = linspace(0,pi,64+1)*ratio-pi/2; % marker for possible phase shifts

    reducedRGBimage = ones(xySize,xySize,3,nFrames, 'uint8'); % allocate
    
    for iFrame = 1:nFrames
        cla(axesHandle)
        
        plot([-1 0.51]*diameter(3),[ 0  0   ]*diameter(3),'-','Color',RGB.brightGrey,'LineWidth',3*liSc) % horizontal coordinateSystem
        plot([ 0  0  ]*diameter(3),[1  -0.51]*diameter(3),'-','Color',RGB.brightGrey,'LineWidth',3*liSc) % vertival coordinateSystem
        
        drawSpurWheel(center_UD_wheel,teeth(1),module,RGB.grey      ,2.5*liSc,RGB.black, angles_UD_wheel(iFrame)); % Up-Down-Wheel [at lower left]  (fast)
        drawSpurWheel(centerIdler,    teeth(2),module,RGB.brightGrey,2.5*liSc,RGB.black,-anglesIdlerToothAllign(iFrame)); % Idler-Wheel [at top left]
        drawSpurWheel(center_LR_wheel,teeth(3),module,RGB.brightGrey,2.5*liSc,RGB.black, angles_LR_wheelToothAllign(iFrame)); % Left-Right-Wheel [at top right] (slow)
        
        x_UD_Crank = cos(angles_UD_wheel(iFrame))*0.9*diameter(3)/2+center_UD_wheel(1); % Up-Down-Wheel
        y_UD_Crank = sin(angles_UD_wheel(iFrame))*0.9*diameter(3)/2+center_UD_wheel(2); % Up-Down-Wheel
        
        if ratio < 1 % draw extra crank
            rotM = [cos(angles_UD_wheel(iFrame)) -sin(angles_UD_wheel(iFrame)); -sin(-angles_UD_wheel(iFrame)) cos(angles_UD_wheel(iFrame))]; % rotation matrix
            vecTemp = rotM*x_y_Crank; % rotate crank
            patch(vecTemp(1,:)+center_UD_wheel(1),vecTemp(2,:)+center_UD_wheel(2),RGB.grey,'EdgeColor',RGB.black,'LineWidth',2*liSc) % raw the crank trapezoid
        end
        
        x_LR_Crank00   = NaN; y_LR_Crank00   = NaN; % Left-Right-Wheel (defaults)
        x_LR_Crank0125 = NaN; y_LR_Crank0125 = NaN; % Left-Right-Wheel (defaults)
        x_LR_Crank025  = NaN; y_LR_Crank025  = NaN; % Left-Right-Wheel (defaults)
        x_LR_Crank05   = NaN; y_LR_Crank05   = NaN; % Left-Right-Wheel (defaults)
        
        if contains(curVers,'p00') % Phase shift 0
            x_LR_Crank00   =  sin(           angles_LR_wheel(iFrame))*0.9*diameter(3)/2+center_LR_wheel(1); % Left-Right-Wheel (if used)
            y_LR_Crank00   = -cos(           angles_LR_wheel(iFrame))*0.9*diameter(3)/2+center_LR_wheel(2); % Left-Right-Wheel (if used)
        end
        if contains(curVers,'p0125') % Phase shift 1/8*pi = 0.125*pi
            x_LR_Crank0125 =  sin(pi/8*ratio+angles_LR_wheel(iFrame))*0.9*diameter(3)/2+center_LR_wheel(1); % Left-Right-Wheel (if used)
            y_LR_Crank0125 = -cos(pi/8*ratio+angles_LR_wheel(iFrame))*0.9*diameter(3)/2+center_LR_wheel(2); % Left-Right-Wheel (if used)
        end
        if contains(curVers,'p025') % Phase shift 1/4*pi = 0.25*pi
            x_LR_Crank025  =  sin(pi/4*ratio+angles_LR_wheel(iFrame))*0.9*diameter(3)/2+center_LR_wheel(1); % Left-Right-Wheel (if used)
            y_LR_Crank025  = -cos(pi/4*ratio+angles_LR_wheel(iFrame))*0.9*diameter(3)/2+center_LR_wheel(2); % Left-Right-Wheel (if used)
        end
        if contains(curVers,'p05') % Phase shift 1/2*pi = 0.5*pi
            x_LR_Crank05   =  sin(pi/2*ratio+angles_LR_wheel(iFrame))*0.9*diameter(3)/2+center_LR_wheel(1); % Left-Right-Wheel (if used)
            y_LR_Crank05   = -cos(pi/2*ratio+angles_LR_wheel(iFrame))*0.9*diameter(3)/2+center_LR_wheel(2); % Left-Right-Wheel (if used)
        end
        
        plot([center_UD_wheel(1) x_UD_Crank ],[center_UD_wheel(2) y_UD_Crank ],'-','Color',RGB.black ,'LineWidth',3*liSc) % base line
        plot([0 sin(angles_LR_wheel(iFrame))*0.9*diameter(3)/2]+center_LR_wheel(1),[0 -cos(angles_LR_wheel(iFrame))*0.9*diameter(3)/2]+center_LR_wheel(2),'-','Color',RGB.black,'LineWidth',3*liSc) % base line
        
        for mark = 1:a-1
            [X,Y] = pol2cart(2*mark*pi/a +angles_UD_wheel(iFrame),[0.9 0.6]*diameter(1)/2);
            X = X+center_UD_wheel(1); % center offset
            Y = Y+center_UD_wheel(2); % center offset
            plot(X,Y,'-','Color',RGB.black,'LineWidth',3*liSc) % rotation marker line
        end
        
        for mark = 1:b-1
            [X,Y] = pol2cart(2*mark*pi/b +angles_LR_wheel(iFrame)-pi/2,[0.9 0.6]*diameter(3)/2);
            X = X+center_LR_wheel(1); % center offset
            Y = Y+center_LR_wheel(2); % center offset
            plot(X,Y,'-','Color',RGB.black,'LineWidth',3*liSc) % rotation marker line
        end
        
        [X,Y] = pol2cart(anglesPSmakerXw+angles_LR_wheel(iFrame),0.9*diameter(3)/2);
        X = X+center_LR_wheel(1); % center offset
        Y = Y+center_LR_wheel(2); % center offset
        plot(X,Y,'-','Color',RGB.grey,'LineWidth',5*liSc) % marker for possible phase shifts
        plot(X(1:8:end), Y(1:8:end) ,'.','Color',RGB.grey,'MarkerSize',30*liSc) % marker for possible phase shifts
        plot(X(1:16:end),Y(1:16:end),'.','Color',RGB.grey,'MarkerSize',45*liSc) % marker for possible phase shifts
        
        plot(xCurvePoints,yCurvePoints0125,'-','Color',RGB.cyan ,'LineWidth',5*liSc) % Lissajous curve
        plot(xCurvePoints,yCurvePoints025, '-','Color',RGB.green,'LineWidth',5*liSc) % Lissajous curve
        plot(xCurvePoints,yCurvePoints05,  '-','Color',RGB.blue ,'LineWidth',5*liSc) % Lissajous curve
        plot(xCurvePoints,yCurvePoints00,  '-','Color',RGB.red  ,'LineWidth',5*liSc) % Lissajous curve
        
        plot([x_UD_Crank max(max(x_LR_Crank00,x_LR_Crank0125),max(x_LR_Crank025,x_LR_Crank05))],[y_UD_Crank y_UD_Crank],':','Color',RGB.paleViolet,'LineWidth',6*liSc) % left crank  to curve
             
        plot([x_LR_Crank0125 x_LR_Crank0125],[y_LR_Crank0125 y_UD_Crank],'.:','Color',RGB.paleCyan, 'LineWidth',6*liSc,'MarkerEdgeColor',RGB.cyan ,'MarkerSize',55*liSc) % crank to curve - verical
        plot([x_LR_Crank025  x_LR_Crank025], [y_LR_Crank025  y_UD_Crank],'.:','Color',RGB.paleGreen,'LineWidth',6*liSc,'MarkerEdgeColor',RGB.green,'MarkerSize',55*liSc) % crank to curve - verical
        plot([x_LR_Crank05   x_LR_Crank05],  [y_LR_Crank05   y_UD_Crank],'.:','Color',RGB.paleBlue, 'LineWidth',6*liSc,'MarkerEdgeColor',RGB.blue ,'MarkerSize',55*liSc) % crank to curve - verical
        plot([x_LR_Crank00   x_LR_Crank00],  [y_LR_Crank00   y_UD_Crank],'.:','Color',RGB.paleRed,  'LineWidth',6*liSc,'MarkerEdgeColor',RGB.red  ,'MarkerSize',55*liSc) % crank to curve - verical
        
        plot(x_UD_Crank,y_UD_Crank ,'.','Color',RGB.violet,'MarkerSize',55*liSc) % color marker on crank
        plot([x_LR_Crank00 x_LR_Crank0125 x_LR_Crank025 x_LR_Crank05],[y_UD_Crank y_UD_Crank y_UD_Crank y_UD_Crank],'o','Color',RGB.violet,'MarkerSize',16*liSc,'LineWidth',4*liSc) % traking points on top of the curve
        
        %% save animation
        xlim(xLimits); ylim(yLimits); % set axis limits
        drawnow
        %  pause(0.01)
        
        if iFrame == 1 % save svg
        %         if ~isempty(which('plot2svg'))
        %             posSave = get(figHandle, 'Position');
        %             set(figHandle, 'Position',[1 1 800 800]); % big start image for antialiasing later [x y width height]
        %             plot2svg(fullfile(pathstr, [fname '_' curVers '.svg']),figHandle) % by Juerg Schwizer
        %             set(figHandle, 'Position',posSave); % reset size
        %         else
        %             disp('plot2svg.m not available; see http://www.zhinst.com/blogs/schwizer/');
        %         end
        end

        f = getframe(figHandle);
        reducedRGBimage(:,:,:,iFrame) = imReduceSize(f.cdata,scaleReduction); % allows subpixel lines
   
    end

    if numel(strfind(curVers,'p')) >= 3 % many curves at once
        nColors = 64;
    else
        nColors = 32;
    end
    
    RGBcurrent = RGB; % copy colormap; to be pruned to the used colors
    if isnan(x_LR_Crank0125)
        RGBcurrent = rmfield(RGBcurrent,{'cyan','paleCyan'}); % remove unused colors
    end
    if isnan(x_LR_Crank025)
        RGBcurrent = rmfield(RGBcurrent,{'green','paleGreen'}); % remove unused colors
    end
    if isnan(x_LR_Crank05)
        RGBcurrent = rmfield(RGBcurrent,{'blue','paleBlue'}); % remove unused colors
    end
    if isnan(x_LR_Crank00)
        RGBcurrent = rmfield(RGBcurrent,{'red','paleRed'}); % remove unused colors
    end

    startMap = cell2mat(struct2cell(RGBcurrent)); % struct2colormap; % list of map colors that are not allowed to be changed
    map = createImMap(reducedRGBimage,nColors,startMap);  % full colormap
    im = uint8(ones(xySize,xySize,1,nFrames)); % allocate
    
    for iFrame = 1:nFrames
        im(:,:,1,iFrame) = rgb2ind(reducedRGBimage(:,:,:,iFrame),map,'nodither'); % rgb to colormap image
    end
    
    imwrite(im,map,fullfile(pathstr, [fname '_' curVers '.gif']),'DelayTime',1/25,'LoopCount',inf) % save gif
    disp([fname '_' curVers '.gif  has ' num2str(numel(im)/10^6 ,4) ' Megapixels']) % Category:Animated GIF files exceeding the 50 MP limit
end

function drawSpurWheel(center,toothNumber,module,fillC,linW,linC,startOffset)
% DRAWSPURWHEEL - draw a simple Toothed Wheel
%    center:       [x y]
%    toothNumber:  scalar
%    module:       scalar tooth "size"
%    fillC:   color of filling [r g b]
%    linW:         LineWidth
%    linC:         LineColor
%    startOffset:  start rotation (scalar)[rad]

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

[X,Y] = pol2cart(angleOffPoints,radiusOffPoints);
X = X+center(1); % center offset
Y = Y+center(2); % center offset
patch(X,Y,fillC,'EdgeColor',linC,'LineWidth',linW)
plot(X,Y,'.','MarkerSize',2*linW,'Color',linC); % extra dots make corners look smoother


% %% effective Radius
% circle(center(1),center(2),effectiveRadius,linC,'-.',linW);

%% shaft
shaftRadius = module*6 /2; % small radius, assuming the effective radius a 6-tooth wheel would have
circle(center(1),center(2),shaftRadius,linC,'-',linW);


function h = circle(x,y,r,col,sty,linW)
% x:    coordinates of the center
% y:    coordinates of the center
% r:    is the radius of the circle
% sty:  LineStyle
% linW: LineWidth
angleOffPoints = linspace(0,2.001*pi,300);
xc = x + r*cos(angleOffPoints);
yc = y + r*sin(angleOffPoints);
h = plot(xc,yc,'Color',col,'LineWidth',linW,'LineStyle',sty);


function im = imReduceSize(im,redSize)
% Input:
%  im:      image, [imRows x imColumns x nChannel x nStack] (unit8)
%                      imRows, imColumns: must be divisible by redSize
%                      nChannel: usually 3 (RGB) or 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:     [imRows/redSize x imColumns/redSize x nChannel x nStack] (unit8)
%
% an alternative is : imNew = imresize(im,1/scaleReduction ,'bilinear');
%        BUT 'bicubic' & 'bilinear'  produces fuzzy lines
%        IMHO this function produces nicer results as "imresize"
 
[nRow,nCol,nChannel,nStack] = 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: [nRow, 1, nColNew*nChannel]
im = permute(im, [3,1,2,4]); % move singleton-dimension-2 to dimension-3; transpose image. Size of result: [nColNew*nChannel, nRow, 1]
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: [nColNew*nChannel, 1, nRowNew]
im = permute(im, [3,1,2,4]); % move singleton-dimension-2 to dimension-3; transpose image back. Size of result: [nRowNew, nColNew*nChannel, 1]
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, [imRows x imColumns x 3(RGB) x nStack] (unit8)
%   nCol:      total number of colors the map should have, [integer]
%   startMap:  predefined colors; colormap format, [p x 3] (double)

imRGB = permute(imRGB,[1 2 4 3]); % step1; make unified column-image (handling possible nStack)
imRGBcolumn = reshape(imRGB,[],1,3,1); % step2; make unified column-image

fullMap = double(permute(imRGBcolumn,[1 3 2]))./255; % "column image" to color map 
[fullMap,~,imMapColumn] = 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(['Number of colors: ' num2str(nColFul) ' (including ' num2str(nColStart) ' self defined)']);

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
    [mDiff,index] = min(diff); % find matching (or most similar) color
    if mDiff>0.05 % color handling is not precise
        warning(['Predefined color ' num2str(iCol) ' does not appear in image'])
        continue
    end
    isThisPreDefCol = imMapColumn==index; % find all pixel with predefined color
    disp([num2str(sum(isThisPreDefCol(:))) ' pixel have predefined color ' num2str(iCol)]);
    isPreDefCol = or(isPreDefCol,isThisPreDefCol); % combine with overall list
end
[~,mapAdditional] = rgb2ind(imRGBcolumn(~isPreDefCol,:,:),nCol-nColStart,'nodither'); % create map of remaining colors
map = [startMap;mapAdditional];

Licensing[edit]

I, the copyright holder of this work, hereby publish it under the following license:
Creative Commons CC-Zero This file is made available under the Creative Commons CC0 1.0 Universal Public Domain Dedication.
The person who associated a work with this deed has dedicated the work to the public domain by waiving all of their rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission.

File history

Click on a date/time to view the file as it appeared at that time.

Date/TimeThumbnailDimensionsUserComment
current22:27, 24 January 2021Thumbnail for version as of 22:27, 24 January 2021527 × 527 (7.77 MB)Jahobr (talk | contribs)upscale to 100 megaPixel limit
16:52, 18 September 2017Thumbnail for version as of 16:52, 18 September 2017370 × 370 (4.77 MB)Jahobr (talk | contribs)GraphicsSmoothing; code update
12:29, 1 May 2017Thumbnail for version as of 12:29, 1 May 2017350 × 350 (4.07 MB)Jahobr (talk | contribs)User created page with UploadWizard

The following 34 pages use this file:

File usage on other wikis

The following other wikis use this file: