Danilo R. Vieira | Oceanógrafo

Aqui estão algumas das coisas que eu aprendi, descobri ou fiz (por obrigação ou por diversão). Espero que encontre algo que seja útil para você.

MATLAB → Gráficos

Árvore de Natal em MATLAB

Este é um código MATLAB para criar uma árvore de natal 3D e animada (luzes piscando e neve caindo). A inspiração veio de diversas outras árvores de natal em MATLAB existentes na internet (pode procurar, elas existem). O diferencial dessa são as partes animadas e os presentes tridimensionais.

Conteúdo

Preparação

% A mensagem
msg = char([70 101 108 105 122 32 78 97 116 97 108 33]);

% Simplificando o cellfun para nao ter que digitar os dois últimos
% parametros sempre
cf = @(f,p)(cellfun(f, p, 'UniformOutput', 0));

% Ajusta o tamanho da figura, centraliza na tela e acerta outros parâmetros
s_sz = get(0, 'ScreenSize');
f_sz = s_sz(3:4) * 0.5;
figure('Units', 'Pixels', 'Position', [(s_sz(3:4)-f_sz)./2 f_sz], ...
       'ToolBar', 'none', 'Name', msg, 'Renderer', 'OpenGL', ...
       'NumberTitle', 'off', 'Color', [.6 .6 1], 'MenuBar','none');

A árvore

% Isso gera a árvore, a função 'cylinder' cria um solido de revolução de
% altura unitária, a partir de um vetor de raios
[x y z] = cylinder([ones(1,7)*.5 (1.96:-.04:0)], 255);

% Aqui amassamos a árvore para dar a ilusão de folhas individuais e do
% tronco enrrugado. Note o z multiplicado por 5, para definir a altura
% final da árvore
amassa = @(m)(m .* (rand(size(m)) * .05 + .975));
C = cf(amassa, {x y z*5});

% Plota a árvore
surfl(C{1}, C{2}, C{3}, 'light');

% Cria um colormap com o tronco marrom e um verde com gradiente
colormap([repmat([.3 .24 .02],7,1); zeros(50,1) (.2:.01:0.69)' zeros(50,1)]);
shading interp;
% O titulo em letras grandes
title(['{\bf \fontsize{16} ' msg '}']);

Os acessórios

% Escolhe pontos na árvore que receberão as luzes piscantes, pegamos de 8
% ao final para garantir que não haverá luzes no tronco
D = cf(@(m)(m(8:end,:)), C);
dec = randperm(numel(D{1}));
I = cf(@(in)(dec(in:in+49)), num2cell(1:50:151));

% xp, yp e zp formam um cubo de lado unitário
xp = [0 1 0 0 0 0; 0 1 0 1 1 1; 1 1 0 1 1 1; 1 1 0 0 0 0];
yp = [0 0 0 1 0 0; 0 1 1 1 0 0; 0 1 1 1 1 1; 0 0 0 1 1 1];
zp = [0 0 0 0 1 0; 1 0 0 0 1 0; 1 1 1 1 1 0; 0 1 1 1 1 0];
% Com essa função podemos criar os presentes achatando, esticando e movendo
% um cubo
cubo = @(x,y,z,l,c,a,s)(patch(xp*l+x, yp*c+y, zp*a+z, s));

% As cores dos enfeites
enfeites = {'r','g','y','c'};
% As cores em uma função que retorna uma ordem diferente para cada chamada,
% assim as cores podem ser alternadas, fazendo as luzes piscarem
cores = @()(cell2mat(enfeites(randperm(4))));

% Posição inicial da neve, note que usa-se a função 'amassa' para deixar a
% posição da neve aleatoria
[nx, ny, nz] = meshgrid(linspace(-3,3,5), linspace(-3,3,5), 0:0.25:7);
N = cf(amassa, {nx(:) ny(:) nz(:)});

hold on
% Plota as luzes e guarda o handle para poder fazer elas piscarem mais
% adiante
h = cellfun(@(in,s)(plot3(D{1}(in),D{2}(in),D{3}(in), ['d' s], 'MarkerFaceColor', s, 'MarkerEdgeColor', 'none')), I, enfeites);
% Plota a neve e guarda o handle para faze-la cair mais adiante
n = plot3(N{1}, N{2}, N{3}, 'xw');
% Cria os presentes e faixas decorativas para as caixas
arrayfun(cubo, [-2 -1.6 -1.7 -0.5 -0.51 -3], [-1.5 -1.52 -1.2 -2.1 -2.11 -3], ...
    [0 -0.01 0.25 0 0.2 0], [1 0.2 0.5 0.7 0.72 6], [1 1.02 0.5 1 1.02 6], ...
    [0.25 0.27 0.3 0.6 0.2 -1e-5], 'rkgbrw');
hold off

% Ajusta a posição da camera
view(-34, 6);

% Seria estranho uma árvore de natal com eixo cartesiano…
axis equal off;

% Limita o eixo z
zlim([0 5]);

Animando

% Reseta o passo de tempo
t_pos = 0;

% 'while 1' equivale a 'para sempre'
while 1
    % Se o passo de tempo for par, pisca as luzes
    if rem(t_pos,2), arrayfun(@(x,s)(set(x, 'MarkerFaceColor', s)), h, cores()); end
    % A variavel N recebe a posição atual da neve
    Nz = get(n, 'ZData');
    % Faz a neve cair 0.25 unidades
    Nz = Nz-0.25;
    % Devido a corte de custos, a neve que ja caiu no chão será mandada
    % para cima para cair de novo
    Nz(Nz <= 0) = 7;
    % Depois de ajustar os novos valores atualizamos a neve
    set(n, 'ZData', Nz);
    % Atualiza o passo de tempo
    t_pos = t_pos+1;
    % Manda o matlab desenhar, agora.
    drawnow;
    % Espera um 1/4 de segundo…
    pause(0.25);
end