2 votes

Code efficace pour dessiner un triangle de sierpinski avec matlab

Voici mon code :

function sierpinski(A, B, C, n)
    if n == 0
        patch([A(1), B(1), C(1)], [A(2), B(2), C(2)], [0.0 0.0 0.0]);
    else
       sierpinski(A, (A + B)/2, (A + C)/2, n-1);
       sierpinski(B, (B + A)/2, (B + C)/2, n-1);
       sierpinski(C, (C + A)/2, (C + B)/2, n-1);
end

% sierpinski([0 0], [1 0], [.5 .8], 8)

Ce n'est pas très efficace. Je veux d'abord générer toutes les données puis patcher, mais je ne sais pas comment l'utiliser correctement. Aussi, mon code peut-il être écrit en utilisant des boucles for ?

8voto

Chris Taylor Points 25079

Votre idée d'écrire une fonction pour générer les données et une autre pour les tracer est bonne. C'est souvent une bonne idée de séparer la génération des données du traitement, et le traitement de la sortie. Je procéderais de la manière suivante :

function out = sierpinski(a, b, c, n)

    if n == 0
        out.xvals = [a(1), b(1), c(1)];
        out.yvals = [a(2), b(2), c(2)];
    else
        out1 = sierpinski(a, (a+b)/2, (a+c)/2, n-1);
        out2 = sierpinski(b, (a+b)/2, (b+c)/2, n-1);
        out3 = sierpinski(c, (a+c)/2, (b+c)/2, n-1);
        out = [out1, out2, out3];
    end

end

Cela crée une structure de longueur 3^n dont chaque entrée contient les coordonnées de l'un des petits triangles du triangle de Sierpinski. Votre code pour le tracer pourrait alors ressembler à

>> out = sierpinski([0,0], [1,0], [0.5, sqrt(3)/2], 8);
>> figure(); hold on;
>> for i = 1:length(out)
       patch(out(i).xvals, out(i).yvals, 'k');
   end

Cela se plante sur ma machine (il semble que Matlab ne gère pas très bien des milliers de patchs sur le même graphique) mais une boucle similaire qui trace un point au coin de chaque petit triangle.

>> x = [out.xvals];
>> y = [out.yvals];
>> plot(x, y, '.');

ce qui donne ce graphique

enter image description here

0voto

sebastian Points 4304

Je n'ai pas d'exemples de code prêts, mais.. :

Au lieu de dessiner chaque triangle en tant qu'objet patch unique, vous pourriez essayer de dessiner tous les triangles en un seul grand patch. En fait, il suffit de concaténer les coordonnées x et y de chaque triangle en les séparant par un NaN, ce qui empêchera le patch de dessiner des lignes reliant les triangles individuels. Par exemple, la ligne suivante produit deux triangles séparés :

p = patch( [0 0.5 1 0 NaN 2 2.5 3 2 NaN ], [ 0 1 0 0 NaN 2 3 2 2 NaN], 'k')

Attention, pour avoir un triangle fermé, il faut 4 points par triangle de cette façon, le dernier point étant identique au premier.

0voto

EDIT : Pour chaque niveau de récursion, vous pouvez "effacer" les triangles centraux, de sorte que vous devez patcher beaucoup moins de triangles. Par exemple, au premier niveau, vous avez trois triangles 'haut' et un seul triangle 'bas'. Vous pouvez tracer ce triangle, au lieu des trois autres. Une routine plus compacte est :

function sierpinski(rec)
  [x, x0] = deal(cat(3, [1 0]', [-1 0]', [0 sqrt(3)]')); 
  for k = 1 : rec x = x(:,:) + x0 * 2 ^ k / 2; 
end 
patch('Faces', reshape(1 : 3 * 3 ^ k, 3, '')', 'Vertices', x(:,:)') 
end

Vous devez donc remplir beaucoup moins de triangles si...

function sierpinski(rec)
close all
%Main Triangle
hFig=figure;
units=get(hFig,'units');
set(hFig,'units','normalized','outerposition',[0 0 1 1], 'Color', 'white');
set(hFig,'units',units); clear units
hold on
Vx=[0 0.5 1]; Vy=[0 realsqrt(3)/2 0];
fill(Vx,Vy,'b')
%the number of white triangles = sum(3.^(0:1:rec-1))
whitex=NaN(3,sum(3.^(0:1:rec-1))); whitey=whitex; K=1;
for S=1:rec
    [Vx,Vy]=sierpinskisect;
end
fill(whitex,whitey,'w')

function [outX,outY]=sierpinskisect
    %the number of blue triangles = 3^S
    L=size(Vx,1);
    outX=NaN(3*L,3); outY=outX; J=1;
    for I=1:L
        %left blue triangle
        outX(J,:)=[Vx(I,1) mean(Vx(I,(1:2))) mean(Vx(I,([1 3])))];
        outY(J,:)=[Vy(I,1) mean(Vy(I,(1:2))) mean(Vy(I,([1 3])))];
        J=J+1;
        %right blue triangle
        outX(J,:)=[mean(Vx(I,([1 3]))) mean(Vx(I,(2:3))) Vx(I,3)];
        outY(J,:)=[mean(Vy(I,([1 3]))) mean(Vy(I,(2:3))) Vy(I,3)];
        J=J+1;
        %upper blue triangle
        outX(J,:)=[mean(Vx(I,(1:2))) Vx(I,2) mean(Vx(I,(2:3)))];
        outY(J,:)=[mean(Vy(I,(1:2))) Vy(I,2) mean(Vy(I,(2:3)))];
        J=J+1;
        %white triangle
        whitex(:,K)=[outX(J-3,2);outX(J-3,3);outX(J-2,2)];
        whitey(:,K)=[outY(J-3,2);outY(J-3,3);outY(J-2,2)];
        K=K+1;
    end
end

fin

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X