File:Dragon Curve adding corners trails rectangular numbered L.gif
From Wikimedia Commons, the free media repository
Jump to navigation
Jump to search
Dragon_Curve_adding_corners_trails_rectangular_numbered_L.gif (504 × 341 pixels, file size: 5.68 MB, MIME type: image/gif, looped, 580 frames, 35 s)
File information
Structured data
Captions
Summary
[edit]DescriptionDragon Curve adding corners trails rectangular numbered L.gif |
English: Animation of a Dragon curve. The order is increased from 0 to 15.
0: • • 1: • L • 2: • L L R • 3: • L L R L L R R • 4: • L L R L L R R L L L R R L R R • 5: •LLRLLRRLLLRRLRRLLLRLLRRRLLRRLRR• |
Date | |
Source | Own work |
Author | Jahobr |
Other versions |
[edit] |
GIF development InfoField | |
Source code InfoField | MATLAB codefunction Dragon_Curve_adding_corners_gif()
% Programmed in Matlab R2017a.
% Animation of an Dragon Curve unfolding.
% Several versions of the unfolding curve as gif files are created.
% left 'L' and right 'R' with and without a trails.
%
% 2019-05-30 Jahobr - Licensing: CC0 1.0 Universal Public Domain Dedication
[pathstr,fname] = fileparts(which(mfilename)); % save files under the same name and at file location
fname = strrep(fname,'_gif','');
maxOrder = 15; % final order of fractal
greenCol = round([0.1 0.7 0.1]*255)/255; % green
redCol = round([1 0 0 ]*255)/255; % red
greenFadeWhiteCol = round([0.5 0.9 0.5]*255)/255; % green
redFadeWhiteCol = round([1 0.5 0.5]*255)/255; % red
greenFadeBlackCol = round([0.1 0.35 0.1]*255)/255; % green
redFadeBlackCol = round([0.5 0 0 ]*255)/255; % red
% stop acc rot deacc stop
accFrames = 8; % frames for acceleration (first frame will be 0 last at full speed, so practicall it is accFrames-2)
speed = [linspace(0,1,accFrames) ones(1,21) linspace(1,0,accFrames)];
speed = speed(1:end-1); % last speed is 0, this does nothing in cumsum; (compensated by +1 frames in center)
displacementList = cumsum(speed)/sum(speed); % create position, normalize,
xLimits = [-0.36,1.19];
yLimits = [-0.36,0.69];
xRange = xLimits(2)-xLimits(1);
yRange = yLimits(2)-yLimits(1);
figHandle = figure(6765301); clf;
set(figHandle,'Units' ,'pixel');
set(figHandle,'Color' ,'white'); % white background
set(figHandle,'Units' ,'pixel');
set(figHandle,'MenuBar','none', 'ToolBar','none'); % free real estate for a maximally large image
axesHandle = axes; hold(axesHandle,'on');
axis equal
axis off % invisible axes (no ticks)
drawnow;
p1 = 50; % determined by trial an error
p2 = 300; % determined by trial an error
for mode = {'minimalist','trails'} %
iFrame = 0; % init
x = [0 1]; % initial Line
y = [0 0]; % initial Line
switch mode{1}
case {'minimalist'}
nFramesMove = 1+ (length(displacementList)-1)*maxOrder; % inital Frame + (rotation - redundant frame)*order
nFramesFadeOut = 5; % fade to white
nFramesFadeIn = 4; % from white to first image (white not included)
nFrames= nFramesMove + nFramesFadeOut + nFramesFadeIn;
liWidth = [ones(1,p1)*26 linspace(26,8,p2-p1) linspace(8,2,nFrames-p2)];
displacementIndexList = 1:numel(displacementList); % index "1" (only used in orderr=1) otherwise there would be redundant frames
% List will be: 1 2 3 ... end 2 3 ... end 2 3 ... end %
% "1" and "end" are full dragon curves; all other numbers are moving
case {'trails'}
nFramesMove = 1+ (length(displacementList)+2)*maxOrder; % inital Frame + (rotation + intermediate state of the curve)*order
nFramesFadeOut = 5; % fade to white
nFramesFadeIn = 4; % from white to first image (white not included)
nFrames= nFramesMove + nFramesFadeOut + nFramesFadeIn;
liWidth = [ones(1,p1)*26 linspace(26,8,p2-p1) linspace(8,2,nFrames-p2)]; % LineWidth defined
displacementIndexList = 0:numel(displacementList)+2; % index "0" (only used in orderr=1) and "+1" for the pure dragon curve without trails
% List will be: 0 1 2 3 ... end end+1 1 2 3 ... end end+1 2 3 ... end end+1
% "0" and "end+1" are full dragon curves;
% "1" and "end" are full dragon curves; but with colorful path plots visible
% all other numbers are moving
end
delayTime = ones(1,nFrames)*1/25; % delay per frame
screenSize = get(groot,'Screensize')-[0 0 5 20]; % [1 1 width height] (minus tolerance for figure borders)
imageAspectRatio = xRange/yRange;
MegaPixelTarget = 100*10^6; % Category:Animated GIF files exceeding the 100 MP limit
pxPerImage = MegaPixelTarget/nFrames; % pixel per gif frame
ySize = sqrt(pxPerImage/imageAspectRatio); % gif height
xSize = ySize*imageAspectRatio; % gif width
xSize = floor(xSize); ySize = floor(ySize); % full pixels
scaleReduction = min(...% repeat as often as possible for nice antialiasing
floor(screenSize(4)/ySize), floor(screenSize(3)/xSize));
if scaleReduction == 0; error('"MegaPixelTarget" not possible; use smaller target or bigger monitor'); end % check
liWidth = liWidth/sqrt(1000)*sqrt(xSize*scaleReduction); % re-scale if image is not original design size
set(figHandle, 'Position',[1 1 xSize*scaleReduction ySize*scaleReduction]); % big start image for antialiasing later [x y width height]
set(axesHandle,'Position',[0 0 1 1]); % stretch axis as big as figure, [x y width height]
xlim(xLimits); ylim(yLimits);
reducedRGBimageRight = uint8(ones(ySize,xSize,3,nFrames)); % allocate
reducedRGBimageLeft = reducedRGBimageRight; % allocate
for orderr = 1:maxOrder
nPoinitsOld = length(x);
nPoinitsAdd = nPoinitsOld-1;
addX = zeros(1,nPoinitsAdd); % allocate
addY = zeros(1,nPoinitsAdd); % allocate
xMean = mean([x(1:end-1); x(2:end)],1); % center on each line segment
yMean = mean([y(1:end-1); y(2:end)],1); % center on each line segment
xDiff = diff(x); % for scaling to current grid size
yDiff = diff(y); % for scaling to current grid size
nPoinitsNew = nPoinitsOld+nPoinitsAdd;
oldPos = 1:2:nPoinitsNew; % index in newX of already existing coners
addPos = 2:2:nPoinitsNew-1; % index in newX of newly created coners
newX = zeros(1,nPoinitsNew); % allocate
newY = zeros(1,nPoinitsNew); % allocate
newX(oldPos) = x; % known, non moving base points
newY(oldPos) = y; % known, non moving base points
for iDispl = displacementIndexList %
iFrame = iFrame+1; % next frame
switch mode{1}
case {'minimalist'}
plotTrails = false; %
displacement = displacementList(iDispl)*0.5;
if iDispl == 1
if orderr == 1 % only the very first frame of the animation;
delayTime(iFrame) = 0.8; % keep completed order frames longer
else % orderr ~= 1 % iDispl=end,orderr=x and iDispl=1,orderr=x+1 are the same image
iFrame = iFrame-1; % revert
continue % skip
end
elseif iDispl == displacementIndexList(end)
if orderr == maxOrder % only the very last frame of the animation;
delayTime(iFrame) = 2.5; % keep max curve on screen for a while
else % orderr ~= 1 % iDispl=end,orderr=x and iDispl=1,orderr=x+1 are the same image
delayTime(iFrame) = 0.5; % keep completed order frames longer
end
end
case {'trails'}
% List will be: 0 1 2 3 ... end end+1 1 2 3 ... end end+1 2 3 ... end end+1
% "0" and "end+1" are full dragon curves;
% "1" and "end" are full dragon curves; but with colorful path plots visible
% all other numbers are moving
plotTrails = 1; % default
if iDispl == 0
if orderr == 1 % only the very first frame of the animation
displacement = 0;
plotTrails = 0; %
delayTime(iFrame) = 0.8; % keep completed order frames longer
else % orderr ~= 1 % only the very first frame of the animation
iFrame = iFrame-1; % revert
continue % skip
end
elseif iDispl == 1
delayTime(iFrame) = 0.2; % movement starts, keep frames longer
displacement = displacementList(iDispl)*0.5;
elseif iDispl == numel(displacementList)
delayTime(iFrame) = 0.2; % movement ends, keep frames longer
displacement = displacementList(iDispl)*0.5;
elseif iDispl == numel(displacementList)+1 % at the end of each modification fade out trails
plotTrails = 0.5; % fade out trails
displacement = 0.5;
elseif iDispl == numel(displacementList)+2 % at the end of each modification plot pure dragon curve
displacement = 0.5;
plotTrails = 0; %
if orderr == maxOrder % only the very last frame of the animation;
delayTime(iFrame) = 2.5; % keep max curve on screen for a while
else % orderr ~= 1 % iDispl=end,orderr=x and iDispl=1,orderr=x+1 are the same image
delayTime(iFrame) = 0.3; % keep completed order frames longer
end
else % normal Frame
displacement = displacementList(iDispl)*0.5;
end
end
addX(1:2:end) = xMean(1:2:end) - displacement*yDiff(1:2:end); % 1st 3rd ... anti-clockwise
addY(1:2:end) = yMean(1:2:end) + displacement*xDiff(1:2:end); % 1st 3rd ... anti-clockwise
addX(2:2:end) = xMean(2:2:end) + displacement*yDiff(2:2:end); % 2nd 4th ... clockwise
addY(2:2:end) = yMean(2:2:end) - displacement*xDiff(2:2:end); % 2nd 4th ... clockwise
newX(addPos) = addX; % moving points
newY(addPos) = addY; % moving points
cla(axesHandle) % fresh frame
plot(0, 0,'.w'); % dummy, it is needed trust me
trailsHand = []; % default init
if plotTrails>0 % not during the "pure dragon curve"-frames marked with pseudo iDispl "0" and "-1"
trailsXroot = x(1:end-1)+displacement*xDiff;
trailsYroot = y(1:end-1)+displacement*yDiff;
if plotTrails == 1
colTrailsOdd = redCol;
colTrailsEven = greenCol;
else % plotTrails == 0.5
colTrailsOdd = redFadeWhiteCol; % fading out
colTrailsEven = greenFadeWhiteCol; % fading out
end
signFlip = ones(size(trailsXroot));
signFlip(2:2:end) = -1; % every second diffent direction
trailsHand = plot(...
[trailsXroot; xMean; xMean-displacement*yDiff.*signFlip],...
[trailsYroot; yMean; yMean+displacement*xDiff.*signFlip],...
'.-','Color',colTrailsOdd, 'LineWidth',liWidth(iFrame)*0.7, 'MarkerSize',0.7*3.4*liWidth(iFrame));
set(trailsHand(2:2:end),'Color',colTrailsEven); % every second diffent color
end
plot(newX,newY,'k.-','LineWidth',liWidth(iFrame),'MarkerSize',3.4*liWidth(iFrame)); % dragon curve
dotHandOdd = []; % default init
dotHandEven = []; % default init
if plotTrails>0 % not during the "pure dragon curve"-frames marked with pseudo iDispl "0" and "-1"
if plotTrails == 1
colDotsOdd = redCol;
colDotsEven = greenCol;
else % plotTrails == 0.5
colDotsOdd = redFadeBlackCol; % fading out
colDotsEven = greenFadeBlackCol; % fading out
end
dotHandOdd = plot(addX(1:2:end),addY(1:2:end),'.','Color',colDotsOdd, 'MarkerSize',liWidth(iFrame)*2); % anti-clockwise displaced points
dotHandEven = plot(addX(2:2:end),addY(2:2:end),'.','Color',colDotsEven,'MarkerSize',liWidth(iFrame)*2); % clockwise displaced points
end
if displacement < 0.25
text_s = num2str(orderr-1); % order string
co = interp1([-10 0.1 0.15 10],[0 0 1 1],displacement);
else
text_s = num2str(orderr); % order string
co = interp1([-10 0.35 0.4 10],[1 1 0 0],displacement);
end
text(0.025*xSize*scaleReduction,0.03*ySize*scaleReduction,text_s,... % add order text
'FontName','Helvetica Narrow','Color',co*[1 1 1],...
'FontUnits','pixels','Units','pixel',...
'FontSize',0.09*xSize*scaleReduction,'FontWeight','bold',...
'HorizontalAlignment','left','VerticalAlignment','baseline');
xlim(xLimits); ylim(yLimits);
%% save animation
drawnow;
f = getframe(figHandle);
reducedRGBimageRight(:,:,:,iFrame) = imReduceSize(f.cdata,scaleReduction); % the size reduction: adds antialiasing
%% flip top bottom (and red / green)
objectList = findobj(axesHandle,'Type','line'); %
valuesY = get(objectList,'YData');
for i = 1:length(objectList)
set(objectList(i),'YData',-valuesY{i})
end
if ~isempty(dotHandOdd)
set(dotHandOdd, 'Color',colDotsEven); % flip colors
set(trailsHand(1:2:end),'Color',colTrailsEven); % every second diffent color
end
if ~isempty(dotHandEven)
set(dotHandEven,'Color',colDotsOdd); % flip colors
set(trailsHand(2:2:end),'Color',colTrailsOdd); % every second diffent color
end
ylim(fliplr(-yLimits));
drawnow;
f = getframe(figHandle);
reducedRGBimageLeft(:,:,:,iFrame) = imReduceSize(f.cdata,scaleReduction); % the size reduction: adds antialiasing
end
x = newX; % update base structure
y = newY; % update base structure
end
whiteImage = ones([ySize,xSize,3,1],'uint8')*255; % allocate
if nFramesFadeOut>0
brightnes = linspace(1,0,nFramesFadeOut+1);
brightnes = brightnes(2:end); % first "1" not needed
for iFrame = 1:nFramesFadeOut % fade to white
reducedRGBimageLeft (:,:,:,nFramesMove + iFrame) = whiteImage-(whiteImage-reducedRGBimageLeft (:,:,:,nFramesMove))*brightnes(iFrame); % brightness reduction
reducedRGBimageRight(:,:,:,nFramesMove + iFrame) = whiteImage-(whiteImage-reducedRGBimageRight(:,:,:,nFramesMove))*brightnes(iFrame); % brightness reduction
end
end
if nFramesFadeIn>0
brightnes = linspace(0,1,nFramesFadeIn+2);
brightnes = brightnes(2:end-1); % first "0" and last "1" not needed
for iFrame = 1:nFramesFadeIn % from white to frame1
reducedRGBimageLeft (:,:,:,nFramesMove+nFramesFadeOut + iFrame) = whiteImage-(whiteImage-reducedRGBimageLeft (:,:,:,1))*brightnes(iFrame); % brightness reduction
reducedRGBimageRight(:,:,:,nFramesMove+nFramesFadeOut + iFrame) = whiteImage-(whiteImage-reducedRGBimageRight(:,:,:,1))*brightnes(iFrame); % brightness reduction
end
end
switch mode{1}
case {'minimalist'}
map = gray(16);
case {'trails'}
map = createImMap(reducedRGBimageLeft,32,[0 0 0;1 1 1;greenCol;redCol]); % colormap
end
for iFrame = 1:nFrames
imLeft = rgb2ind(reducedRGBimageLeft (:,:,:,iFrame),map,'nodither'); % rgb to colormap image
imRight = rgb2ind(reducedRGBimageRight(:,:,:,iFrame),map,'nodither'); % rgb to colormap image
if iFrame == 1
imwrite(imLeft, map,fullfile(pathstr, [fname '_' mode{1} '_rectangular_numbered_L.gif']), 'LoopCount',Inf,'DelayTime',delayTime(iFrame)); % individual timings
imwrite(imRight,map,fullfile(pathstr, [fname '_' mode{1} '_rectangular_numbered_R.gif']), 'LoopCount',Inf,'DelayTime',delayTime(iFrame)); % individual timings
else
imwrite(imLeft, map,fullfile(pathstr, [fname '_' mode{1} '_rectangular_numbered_L.gif']), 'WriteMode','append','DelayTime',delayTime(iFrame)); % individual timings
imwrite(imRight,map,fullfile(pathstr, [fname '_' mode{1} '_rectangular_numbered_R.gif']), 'WriteMode','append','DelayTime',delayTime(iFrame)); % individual timings
end
end
disp([fname '-' mode{1} '_rectangular_numbered_xx.gif has ' num2str(numel(reducedRGBimageLeft)/3/10^6 ,4) ' Megapixels']) % Category:Animated GIF files exceeding the 100 MP limit
end
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/reduceImage,'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:
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.
http://creativecommons.org/publicdomain/zero/1.0/deed.enCC0Creative Commons Zero, Public Domain Dedicationfalsefalse |
File history
Click on a date/time to view the file as it appeared at that time.
Date/Time | Thumbnail | Dimensions | User | Comment | |
---|---|---|---|---|---|
current | 07:25, 30 May 2019 | 504 × 341 (5.68 MB) | Jahobr (talk | contribs) | User created page with UploadWizard |
You cannot overwrite this file.
File usage on Commons
The following 7 pages use this file:
- User:Jahobr/Files with MATLAB code
- User:Jahobr/Fractals
- File:Dragon Curve adding corners minimalist rectangular numbered L.gif
- File:Dragon Curve adding corners minimalist rectangular numbered R.gif
- File:Dragon Curve adding corners trails rectangular numbered L.gif
- File:Dragon Curve adding corners trails rectangular numbered R.gif
- Template:Other versions/Dragon Curve adding corners