Yağmurda Koşmak – Bölüm 2

Çok fazla tartışma yaratan ve “başka işin gücün yok mu!” gibi söylemlere maruz kalmama neden olan yazı serisi ile yeniden karşınızdayım. Bugün incelediğimiz önermeyi olabildiğince detaylandırarak ne kadar işsiz olduğum bilgisini daha fazla kişiye ulaştırmayı hedefliyorum. Önceki yazıda belirttiğim gibi bu yazıda yağmurun yağacağı uzayda bir nesne oluşturarak bu nesnenin farklı hızlarda hareket etmesini sağlayacağız. Daha sonra ise bu nesnenin farklı senaryolarda ne kadar ıslandığını inceleyerek herkesin uykularını kaçıran sorulara cevap arayacağız…

Yazının asıl konusuna geçmeden önce önceki yazıdaki kodlarda yaptığım ufak bir değişikliğe değinmek istiyorum. Önceki yazıda birim zamanda üretilen yağmur damlası sayısını hesapladıktan sonra tam sayıya yuvarlama işlemi yapıyordum. Ancak bu durum yağmur şiddetinin olması gerekenden bir miktar yüksek vaya düşük olmasına neden olabilir. Bu nedenle yağmuru oluşturan fonksiyonu aşağıdaki gibi düzenledim.

% Üretilecek damla sayısının belirlenmesi
ngen = Drop.ngen + Drop.dp;
    
genDrop = floor(ngen);
Drop.dp = ngen - genDrop;

% Damlaların üretimi
Drop.positions = [Drop.positions;
                  Space.size(1)*rand(genDrop, 1), ...
                  Space.size(2)*rand(genDrop, 1), ...
                  Space.size(3)*ones(genDrop, 1)];

Burada ngen üretilecek damla sayısını, Drop.dp önceki damla üretiminden arta kalan kısmı ifade etmektedir. Yani t anında 4.5 adet damla üretilmesi gerektiği hesaplandığında, t anında 4 damla üretiliyor ve 0.5 damla bir sonraki zaman dilimine aktarılıyor. Böylelikle ortalamada ulaşılması gereken yağmur şiddetine tam olarak erişiliyor. Kodların düzenlenmiş halini github reposunda paylaştım. Dilerseniz oradan tam halini inceleyebilirsiniz.

Bu yazıda ise daha önce belirttiğim gibi yağmurun yağacağı uzay içerisinde insanı temsil eden bir nesne tanımlayacağız. Bu nesnenin boyutlarını ve hızını kontrol edebilmemiz gerekmektedir. Buna göre nesnenin bilgilerini aşağıdaki gibi tanımlayabiliriz.

% Nesnenin bilgileri
Object.size = [0.28, 1.75]; % Nesnenin boyutları [m]
Object.velocity = 5;        % Nesnenin hareket hızı [m/sn]
Object.movement = Object.velocity*Time.dt; % Nesnenin hareket vektörü [m]
Object.position = [1, Object.size(2)/2];   % Nesnenin başlangıç konumu [m]
% Nesnenin sınırları
Object.edges = [Object.position(1)-Object.size(1)/2,...
                Object.position(1)+Object.size(1)/2;
                Object.position(2)-Object.size(2)/2,...
                Object.position(2)+Object.size(2)/2];

Burada görüldüğü gibi nesnenin boyutlarını, hızını ve uzay içerisindeki başlangıç konumunu istediğimiz gibi belirleyebiliyoruz. Nesnenin sınırlarını belirten Object.edges değişkeni ise hem görselleştirme, hem de yağmur damlalarının nesneye çarpıp çarpmadığının kontrolü için kullanacağız. Tabii ki değişkenlerin boyutlarından bu kodların iki boyutlu uzay için oluşturulduğunu görebilirsiniz. Neden doğrudan üç boyutta yazmıyorsun diye soracak olursanız. Aslında yazabilirim ancak simülasyon çalışmalarında önce sistemi en basit haliyle oluşturup daha sonra detayları eklemenin hata olasılığını azaltan bir strateji olduğunu düşünüyorum. Şimdi nesneyi hareket ettirecek fonksiyonu yazarak devam edebiliriz.

function [Object] = f_Movement2D(Object, Space, plottingFlag)
% Bu fonksiyon girdi olarak verilen nesnenin konumunu değiştiri ve 
% görselleştirir.
% Girdiler -------
% Object          : Nesnenin bilgilerini içeren structure
% Object.movement : Nesnenin x eksenindeki hareket vektörü
% Object.position : Nesnenin konumu
% Object.edges    : Nesnenin sınırları
% Space           : Nesnenin hareket ettiği uzayın bilgileri
% Space.size      : Uzayın boyutları
% prottingFlag    : Görselleştirme bayrağı
% Çıktılar -------
% Object          : Nesnenin güncellenmiş bilgileri
% Object.position : Nesnenin güncellenmiş konumu
% Object.edges    : Nesnenin güncellenmiş sınırları
% ----------------
    
    % Nesnenin hareketi
    Object.position(1) = Object.position(1) + Object.movement;
    
    % Nesnenin sınırları
    Object.edges = [Object.position(1)-Object.size(1)/2,...
                    Object.position(1)+Object.size(1)/2;
                    Object.position(2)-Object.size(2)/2,...
                    Object.position(2)+Object.size(2)/2];
    
    % Görselleştirme için oluşturulan değişkenler
    Draw.x = [Object.edges(1,1), Object.edges(1,2), Object.edges(1,2), ...
              Object.edges(1,1), Object.edges(1,1)];
    Draw.y = [Object.edges(2,1), Object.edges(2,1), Object.edges(2,2), ...
              Object.edges(2,2), Object.edges(2,1)];
    
    % Nesnenin görselleştirilmesi
    if plottingFlag == true
        plot(Draw.x, Draw.y, 'Black', "LineWidth", 1);
        xlim([0, Space.size(1)]); ylim([0, Space.size(2)]);
        xlabel("X [m]"); ylabel("Y [m]");
    end
end

Burada görüldüğü gibi oluşturduğumuz nesneyi sadece x ekseni doğrultusunda hareket ettiriyoruz. Önceki bölümde yağmurun yağış açısını değiştirebilecek şekilde bir program oluşturduğumuz için nesneyi tek bir doğrultuda hareket ettirmek bizim için yeterli olacaktır. Şimdi zaman döngüsünü yazarak program çıktısını inceleyebiliriz.

% Zaman döngüsü
for i = 1:length(Time.axis)
    
    % Nesnenin hareketi
    Object = f_Movement2D(Object, Space, plottingFlag);
    
    % Görselleştirme
    if plottingFlag
        exportgraphics(f1, gifFile, Append=true);
        drawnow;
        pause(Time.dt);
    end
end

Görüldüğü gibi zaman döngüsünde sadece nesnenin hareketini sağlayan fonksiyon çağırılıyor. Kodların tamamını yine github reposundakimainObjectMove2D.m” dosyasında bulabilirsiniz. Buna göre programın çıktısı Şekil 1’de verildiği gibi oluşmaktadır.

Şekil 1. İki boyutlu uzayda hareket eden nesne

Evet nesnenin şekli her ne kadar insana benzemese de bu küçük detaylara takılmamıza gerek yok bence. 🙂 Diğer yandan yazdığımız kodların nesneyi istediğimiz şekilde hareket ettirdiğini görüyoruz. Şimdi üç boyuta geçerek nesnemizin Şekil 2’de görüldüğü gibi hareket etmesini sağlayabiliriz.

Şekil 2. Üç boyutlu uzayda hareket eden nesne

Harika! Artık üç boyutlu uzayda yağmur yağmasını sağlayan ve bir nesneyi hareket ettiren programlara sahibiz. Bu aşamadan sonra tek yapmamız gereken bu iki kodu uygun bir şekilde birleştirmek. İki programı da birbirine benzer şekilde yazdığımızdan dolayı zaman döngüsünü aşağıdaki gibi düzenleyerek bu işlemi kolaylıkla gerçekleştirebiliriz.

% Zaman döngüsü
for i = 1:length(Time.axis)

    % Yağmur damlalarının üretimi ve hareketi
    Drop = f_Rainfall3D(Drop, Space, plottingFlag); hold on;
    
    % Nesnenin hareketi
    Object = f_Movement3D(Object, Space, plottingFlag); hold off;

    % Cisme temas eden damlaların sayılması
    [Drop, Counter] = f_DropCounter3D(Drop, Object);

    DropCounter = DropCounter + Counter;
    
    % Görselleştirme
    if plottingFlag
        exportgraphics(f1, gifFile, Append=true);
        drawnow;
        pause(Time.dt);
    end
end

Burada görüldüğü gibi zaman döngüsünde öncelikle yağmur damlaları güncelleniyor, daha sonra ise oluşturduğumuz nesne hareket ettiriliyor. Devamında ise nesneye temas eden yağmur damlalarının sayılması ve bu damlaların yok edilmesi için aşağıda verilen f_DropCounter3D fonksiyonu kullanılmaktadır.

function [Drop, Counter] = f_DropCounter3D(Drop, Object)
% Bu fonksiyon cisme temas eden damlaları sayar ve bu damlaları siler
% Girdiler ------
% Drop           : Damlaların bilgilerini içeren structure
% Drop.positions : Damlaların konumları
% Object         : Nesnenin bilgilerini içeren structure
% Object.edges   : Nesnenin sınırları
% Çıktılar ------
% Drop           : Damlaların güncellenmiş bilgileri
% Drop.positions : Güncellenmiş damla konumları
% Counter        : Nesneye temas eden damla sayısı
% ---------------
    
    % Nesneye temas eden damlaların indislerinin belirlenmesi
    Indexes = Drop.positions(:,1)>=Object.edges(1,1) & ...
              Drop.positions(:,1)<Object.edges(1,2)  & ...
              Drop.positions(:,2)>=Object.edges(2,1) & ...
              Drop.positions(:,2)<Object.edges(2,2)  & ...
              Drop.positions(:,3)>=Object.edges(3,1) & ...
              Drop.positions(:,3)<Object.edges(3,2);
    
    % Temas eden damlaların sayısı
    Counter = sum(Indexes);
    
    % Temas eden damlaların silinmesi
    Drop.positions(Indexes, :) = [];
end

Sonuç olarak bu programın çıktısında Şekil 2’de oluşturduğumuz nesnenin önceki yazıda oluşturduğumuz yağmurun altında hareket ettiğini görmeyi bekliyoruz. Şekil 3’teki program çıktısının bu beklentilerimize cevap verdiğini görebilirsiniz.

Şekil 3. Yağmur altında koşan insan simülasyonu

Şekile dikkatli bakacak olursanı bazı damlaların nesneye temas ettikten sonra kaybolduğunu görebilirsiniz. Mükemmel! Sizi bilmem ama benim açımdan en fazla keyif aldığım yazı serisinin bu olduğunu söyleyebilirim. 🙂 Ancak bu yazı yeterince uzun olduğu için nesnenin farklı senaryolarda ne kadar ıslandığını test ettiğimiz bölümleri sonraki yazıya bırakıyorum. O zaman sonraki yazıda görüşene kadar kendinize iyi bakın efendim…

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir