9 Nisan 2021 Cuma

Java'da Thread ve Semaphore Kullanımı Bayram Harçlığı Örneği

Normal Dede, SemaphoreDede, AtomicDede ve SynchronizedDede torunlarına bayram harçlığını doğru bir şekilde dağıtabilecek mi? Bayram harçlığı örneğiyle Java'da Semaphore, Thread, AtomicInteger ve synchronized yapılarının nasıl kullanıldığını göreceğiz.

 

Osmanlı'da Bayram Kutlaması
Osmanlı'da Bayram Kutlaması

Thread Nedir?

Türkçe'mize iş parçacığı olarak geçmiş bulunan thread'ler bir hesaplama işini yürüten yapılara denir. İşlemcide yürüyen işlemlerde (process) bir veya birden fazla thread çalışabilir. Bu sayede yoğun işlem gücü gerektiren işler farklı threadlere bölünüp, işlemcinin en verimli şekilde kullanılmasını sağlayarak daha az zamanda işin bitmesine yardımcı olurlar. Örneğimizde dedelerinin elini öpüp harçlık alacak olan torunları birer Thread içinde modelleyeceğiz.

MultiThread Nedir?

Basit programlarımızı main thread dediğimiz tek bir threadde çalışacak şekilde yazarız. İşler büyüdükçe yeni threadlere ihtiyaç doğar ve çoklu threadli (multithread) yapılar ortaya çıkar. Burada bilmemiz gereken şey, kullandığımız yazılım dilinin multithread programlamaya ne kadar API desteği verdiğidir. Java multithreading ve concurrency konularında oldukça iyi standart api desteği sunuyor. 

İşlemci hızları artık Moore Yasası'na göre hızlanmıyor. İşlemci üreticileri çareyi daha çok çekirdekli işlemciler üretmekte arıyorlar. Doğal olarak yazılım dünyasının geleceği de bu çok çekirdekleri en verimli kullananların olacak. Paralel programlama gün geçtikçe daha çok önem kazanacağa benziyor.

Semaphore Nedir?

Uçak gemilerinde elinde bayraklarla pilotlara işaretler veren adamı hatırladınız mı? Kalkış Yapabilirsin! Kalkışı İptal Et! Bayrakları kullanış şekline göre farklı mesajlar verebilir. Semaphore da ismini bu bayraklı işaretlerden alıyor. Kodlar işlemcide işletilirken bir thread'e sen devam edebilirsin derken, diğerine "Hooop hemşerim nereye? Sen dur!" demek için kullanılan yapılardır, Semaphore.

Java'da Semaphore Kullanımı Örneği
Java'da Semaphore Kullanımı Örneği

Kritik Bölge Sorunu (Critical Section Problem)

Kodumuzda bir data birden fazla thread tarafından paylaşılıyorsa ve değiştirilme ihtimali varsa bu dataya kritik kaynak denir. Birden fazla threadin aynı anda bir kod bloğuna girip oradaki paylaşılan değeri değiştirmeye çalışması sonucu hatalı değerler ve öngörülemeyen sonuçlarla karşılaşabiliriz. Bu probleme kritik bölge problemi deniyor. Örneğimizde dedelerin dağıtmak üzere ellerindeki tuttukları toplam harçlık miktarı kritik kaynağımız olacak. 

Mutual Exclusion / Mutually Exclusive / Mutex Nedir?

Tanımladığımız kritik bölgelere aynı anda sedece bir threadin girebilmesi durumuna mutual exclusion denir. Java'da Semaphore tanımlanırken int permits parametresi alır. Bu kaç tane threadin acquire() çağırmasından sonra gelen threadlerin bloklanacağını bildirir. Örneğin 10 değerini verirsek kritik bölgeye girecek ilk 10 threadin devam etmesine izin verirken 11. thread geldiğinde, içerdeki 10 threadden en az birinin release() metodunu çağırmasını bekler ve 11. threadi bloklar. İçerdeki threadlerden biri release() çağırdığında artık blokaj kalkar ve bloklanan thread devam eder. Koronavirüs tedbirlerince AVM'lerde aynı anda bulunabilen müşteri sayısı kısıtına benzetebiliriz. 100 müşteri sınırı var ise, içeri giren hiç bir müşterinin çıkmadığını varsayarsak, ilk 100 müşteriye giriş izni verilir, 101. müşteri girebilmek için içerden bir müşterinin çıkmasını bekler.

Bu bilgiler göz önüne alındığında, kritik bölgeye yalnızca 1 threadin girmesini istediğimiz durumlarda Semaphore permit değerine 1 veririz. Bu özel durumdaki Semaphore nesneleri mutex olarak da adlandırılır.

synchronized Anahtar Kelimesi

Javada kritik kaynakları korumak amacıyla synchronized anahtar kelimesi kullanılır. Önüne geldiği kod bloğuna veya metoda aynı anda sadece bir threadin girmesine izin verir.

Bayram Harçlığı Dağıtma Örneği

Gelelim eğlenceli bölüme. Dedemiz ve 1000 torunu bir ramazan bayramında bayramlaşacaklar. Dedemiz, elindeki çantada toplam 100 Bin TL tutuyor ve her torununa 100 TL bayram harçlığı vermeyi planlıyor. 1000 torun aynı anda dedenin elini öpüp harçık almaya kalkarsa sonuç ne olur? Eğer kritik kaynağını, çantasını, korumaya almadıysa pek hoş şeyler olmaz tahmin edileceği üzere. 

Örnek projemizdeki sınıflara yakından bakalım.

Torun.java, dededen alacağı harçlık miktarı bilgisini ve başarılı şekilde alıp almadığı bilgisini tutuyor.

 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
 public class Torun {

    private Integer alinacakHarclik;
    
    private boolean harclikAlabildim;

    public Torun(Integer alinacakHarclik) {
        this.alinacakHarclik = alinacakHarclik;
    }

    public void dedeninEliniOp(IDede dede) {

        harclikAlabildim = dede.harclikVer(alinacakHarclik);
    }
    
    public boolean isHarclikAlabildim() {
        return harclikAlabildim;
    }
}

Farklı yöntemler kullanan dedeler tanımlayacağımız için şu şekilde bir IDede.java interface tanımladık.

1
2
3
4
5
6
7
8
public interface IDede {

    public boolean harclikVer(Integer alinacakHarclik);
    
    public Integer getKalanHarclik();

    void setToplamDagitilacakHarclik(Integer toplamDagitilacakHarclik);
} 

Normal Dede'miz çok iyi niyetli. Her gelen toruna sorgu sual sormadan elindekinden veriyor. Dede.java sınıfını şu şekilde tanımladık.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public class Dede implements IDede {

    private Integer toplamDagitilacakHarclik;

    @Override
    public boolean harclikVer(Integer alinacakHarclik) {
    
        toplamDagitilacakHarclik = toplamDagitilacakHarclik - alinacakHarclik;
       
        return toplamDagitilacakHarclik >= 0;
    }
    }

AtomicDede ise elindeki toplam harçlık miktarını AtomicInteger nesnesi kullanarak tutuyor. AtomicInteger sınıfı, üzerindeki eksiltme arttırma gibi işlemleri atomic olarak halledebiliyor ve araya başka thread girmiyor.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public class AtomicDede implements IDede {

    private AtomicInteger toplamDagitilacakHarclik;

    @Override
    public boolean harclikVer(Integer alinacakHarclik) {
         
        toplamDagitilacakHarclik.addAndGet(-alinacakHarclik);
       
        return toplamDagitilacakHarclik.get() >= 0;
    }
}   

SemaphoreDede harçlık verme işini bir kabinde yapıyor ve o kabine aynı anda sadece bir torunu alıyor. Kullandığı Semaphore mutex kilidini kullanarak, harclikVer metoduna ilk giren threadle birlikte acquire() metodu ile Semaphore'daki izin miktarını 1 eksiltiyor. Ve bu ilk giren thread işini bitirene, çıkarken de release() metodunu çağırana kadar da içeriye başka thread almıyor.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class SemaphoreDede implements IDede {

    private Integer toplamDagitilacakHarclik;
    
    private Semaphore mutex = new Semaphore(1);

    @Override
    public boolean harclikVer(Integer alinacakHarclik) {
       
        try {
            mutex.acquire();
           
            toplamDagitilacakHarclik = toplamDagitilacakHarclik - alinacakHarclik;
           
            mutex.release();
        } catch (InterruptedException e) {

            e.printStackTrace();
        }
       
        return toplamDagitilacakHarclik >= 0;
    }

}

Örnek projemizde ElOpmeHarclikAlmaThread.java ismindeki sınıf ile torunun dedenin elini öpmesini simüle edeceğiz.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public class ElOpmeHarclikAlmaThread  extends Thread {

    private IDede dede;
    
    private Torun torun;
    
    public ElOpmeHarclikAlmaThread(IDede dede, Torun torun) {
        this.dede = dede;
        this.torun = torun;
    }

    @Override
    public void run() {

        torun.dedeninEliniOp(dede);
    }

}

BayramKutlama.java sınıfımızda da simülasyon kodlarımız bulunuyor. Torun sayısı kadar Thread oluşturuyor ve başlatıyoruz.Sonra tüm threadlerin bitmesini join() metodu ile bekliyoruz. En sonunda dedenin elinde kalan para miktarının sıfır olmasını bekliyoruz. Sıfır değil ise işler karışmış demektir.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class BayramKutlama {
    
    public void bayraminizKutluOlsun(IDede dede) {
        
        List<ElOpmeHarclikAlmaThread> elOpmeThreadleri = new ArrayList<>();
       
        dede.setToplamDagitilacakHarclik(100000);
       
        int torunSayisi = 1000;
               
        int harclikMiktari = 100;
       
        for(int i = 0; i < torunSayisi; i++) {
           
            Torun torun = new Torun(harclikMiktari);
           
            ElOpmeHarclikAlmaThread elOpmeThread = new ElOpmeHarclikAlmaThread(dede, torun);
           
            elOpmeThreadleri.add(elOpmeThread);
        }
       
       
        for(int i = 0; i < torunSayisi; i++) {
       
            elOpmeThreadleri.get(i).start();
        }
       
       
        // Tum threadlerin bitmesini bekle
        for(int i = 0; i < torunSayisi; i++) {
           
            try {
                elOpmeThreadleri.get(i).join();
               
                if(!elOpmeThreadleri.get(i).getTorun().isHarclikAlabildim()) {
                   
                    System.out.println( (i + 1) + ". Torun harcligini tam alamamis!!");
                }
               
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println(dede.getClass().getSimpleName() + " Bitirdi. Elinde kalan miktar " + dede.getKalanHarclik());
        if(dede.getKalanHarclik() > 0) {
           
            System.out.println(dede.getClass().getSimpleName() + " BASARISIZ!!!");
           
        } else {
           
            System.out.println("Dedenin elinde hic para kalmadi. Berhudar olsunlar!");
        }
    }
}

BayramApp.java sınıfında da tüm dede tiplerimiz için simülasyonumuzu koşturuyoruz. Sonuçları konsola yazdırıyoruz. Üst üste çalıştırarak sonuçların hep aynı olduğunu görüyoruz. Sadece normal Dede sınıfımızda dedemizin elinde kalan miktar sıfırdan farklı oluyor. Diğer dedelerimiz kullandıkları yöntemlerle kritik kaynaklarını korumanın bir yolunu bulmuş görünüyorlar.

Bayram Harçlığı Output
Bayram Harçlığı Output

 

Output:

Dedeler harcliklari dagittiginde ellerinde hic para kalmamasi lazim!
--------
Basliyoruz
--------
Dede Bitirdi. Elinde kalan miktar 2700
Dede BASARISIZ!!!
Dede hesaplama suresi 54

AtomicDede Bitirdi. Elinde kalan miktar 0
Dedenin elinde hic para kalmadi. Berhudar olsunlar!
AtomicDede hesaplama suresi 49

SynchronizedDede Bitirdi. Elinde kalan miktar 0
Dedenin elinde hic para kalmadi. Berhudar olsunlar!
SynchronizedDede hesaplama suresi 51

SemaphoreDede Bitirdi. Elinde kalan miktar 0
Dedenin elinde hic para kalmadi. Berhudar olsunlar!
SemaphoreDede hesaplama suresi 50

Örnek projemizi GitHub'da şuradan indirip kendiniz de deneyebilirsiniz.



6 Nisan 2021 Salı

JTS CBS Kütüphanesi Rehberi 5 - Quadtree Nedir? Java'da Örnek Kullanım

Her düğümünün (node) 4 adet çocuğu (child) olan ağaç (tree) veri yapısına quadtree denir. Genellikle 2 boyutlu bir yüzeyi 4 eşit alana bölmek için kullanılır. Bu bölümler de yinelemeli olarak 4 er eşit parçaya ayrılır. Bu şekilde her bir alan quadtree yapısında tutulur.

 

Quadtree nedir?
Quadtree

Java'da quadtree örneği görselleştirmesini JTS (Java Topology Suite) kütüphanesinde bulunan Quadtree sınıfı ile yapacağız. 

Öncelikle 100 adet rastgele nokta türünde geometri tanımlayalım. Bu noktaları tanımladığımız Quadtree nesnesine ekleyeceğiz. 

quadTree.insert(Envelope itemEnv, Object item);

insert metodu ile verdiğimiz "item" nesnesi Envlope (zarf, kapsam) ile tanımlanan konuma indekslenir. Daha sonra belli bir arama / tarama dikdörtgeni kullanarak quadtree nesnesinde bu alana denk gelen itemler sorgulanır.

quadTree.query(Envelope searchEnv);

query() metodunun Java dokümanında query metodunun döndüğü sonuçlar arasında searchEnv arama alanında olmayan nesnelerin de dönülebileceği belirtilmiş. Yani false positive sonuçlar da dönülebilmektedir. JTS geliştiricileri, sevimsiz bir şekilde, bu false positive sorgu sonuçlarını elemek sorumluluğunu kullanıcıya bırakmışlar. Bu nedenle dönen sorgu sonuçlarını bir kez de tarama poligonuyla kesiştirip, kesişmeyenleri sonuç listesinden sileceğiz. query()'yi kullanmayıp direk poligon ile kesişim hesaplamamamızın sebebi, query metodu ile tree içindeki yüksek sayıdaki nesnelerin çoğunu eleyerek daha az sayıda nesnede kesişim hesaplamamızı sağlaması, bu sayede performans kazancı sağlamasıdır.

Görselleştirme amacıyla, quadTree'ye eklediğimiz tüm noktaları ekrana çizdireceğiz. Arama tarama dikdörgenimizi ve query sorgusundan dönen noktaları, false positive sonuçları temizlemiş bir şekilde, kırmızı renge boyayacağız. Dışarda kalan noktaları maviye boyayacağız.

                GeometryFactory geometryFactory = new GeometryFactory();

                Random randomX = new Random(System.currentTimeMillis());
               
                Random randomY = new Random(System.currentTimeMillis() + 100);
               
                List<Coordinate> noktaKoordinatlari = new ArrayList<>();

                int noktaSayisi = 100;
               
                Point[] noktalar = new Point[noktaSayisi];

                Quadtree quadTree = new Quadtree();
               
                for(int i = 1; i <= noktaSayisi; i++) {
                   
                    int xRandomlySelected = randomX.nextInt(250) + 65;
                   
                    int yRandomlySelected = randomY.nextInt(250) + 50;
                   
                    Coordinate coordinate = new Coordinate(xRandomlySelected, yRandomlySelected);
                   
                    noktaKoordinatlari.add(coordinate);
               
                    noktalar[i-1] = geometryFactory.createPoint(coordinate);
                   
                    quadTree.insert(noktalar[i-1].getEnvelopeInternal(), noktalar[i-1]);
                   
                }
               
                Coordinate[] coordinates = new Coordinate[] { new Coordinate(150, 60), new Coordinate(250, 60),  new Coordinate(250, 250),new Coordinate(150, 250), new Coordinate(150, 60)};
               
                Polygon cercevePoligon = geometryFactory.createPolygon(coordinates);
               
                List<Object> cerceveOlasiKapsananNoktalar = quadTree.query(cercevePoligon.getEnvelopeInternal());
               
                List<Point> falsePositives = new ArrayList<>();
               
                for (Object c : cerceveOlasiKapsananNoktalar) {
                    Point p = (Point) c;
                   
                    System.out.println(p + " intersects polygon: " + cercevePoligon.intersects(p) + " envlope " + p.getEnvelopeInternal());
                   
                    if(!cercevePoligon.intersects(p)) {
                        falsePositives.add(p);
                    }
                }
               
                cerceveOlasiKapsananNoktalar.removeAll(falsePositives);

JTS Quadtree Visualisation
JTS Quadtree Visualisation

Github'daki örnek JTS eğitim projemizdeki QuadtreeGorsellestirme.java sınıfını çalıştırarak görselleştirebilirsiniz.

 Önceki bölümler:

  1.  JTS CBS Kütüphanesi Rehberi  1 - Geometri Modeli
  2.  JTS CBS Kütüphanesi Rehberi  2 - Geometrik İlişki Hesaplamaları 
  3.  JTS CBS Kütüphanesi Rehberi  3 - Geometrik Alan Hesaplamaları
  4.  JTS CBS Kütüphanesi Rehberi 4 - Delaunay Üçgenleme, Voronoi Diyagram, Convex Hull



2 Nisan 2021 Cuma

JTS CBS Kütüphanesi Rehberi 4 - Delaunay Üçgenleme, Voronoi Diyagram, Convex Hull

 Previously on JTS

  1.  JTS CBS Kütüphanesi Rehberi  1 - Geometri Modeli
  2.  JTS CBS Kütüphanesi Rehberi  2 - Geometrik İlişki Hesaplamaları 
  3.  JTS CBS Kütüphanesi Rehberi  3 - Geometrik Alan Hesaplamaları

Merhabalar. JTS (Java Topology Suite) rehberimizin önceki bölümlerinde geometri modellerini tanımış, geometrilerin birbiri ile ilişkilerini incelemiş, daha sonra ise geometrik alan hesaplamaları üzerinde durmuştuk. Bu bölümde ise Delaunay Triangulation üçgenleme algoritması ile nasıl üçgenler oluşturulacağını, Voronoi diyagramı üretmeyi ve convex hull poligonu üretimini göreceğiz. Tüm görselleştirme örnek kodlarına GitHub'da şuradan ulaşabileceğinizi hatırlatarak başlayalım. 

Delaunay Triangulation / Üçgenleme

Delaunay triangulation / üçgenleme algoritması, bir nokta setinden anlamlı üçgenler oluşturma yöntemidir. Yüzey modelleme, (terrain modelling), mesh üretme ve rota planlama gibi alanlarda kullanılabilmektedir. Biz örneğimizde rastgele koordinatlardan oluşan bir nokta seti oluşturup JTS'den DelaunayTriangulationBuilder sınıfını kullanarak bu noktalardan bize üçgenler üretmesini isteyeceğiz. Nokta sayısını 100 ve 1000 yaparak iki defa çalıştırıp çıkan sonuçları görselleştireceğiz. Örnek projemizdeki DelaunayUcgenleme.java sınıfını çalıştırarak görselleştirebilirsiniz.

                GeometryFactory geometryFactory = new GeometryFactory();

                Random randomX = new Random(System.currentTimeMillis());
               
                Random randomY = new Random(System.currentTimeMillis() + 100);
               
                List<Coordinate> coords = new ArrayList<>();

                int noktaSayisi = 100;

                for(int i = 1; i <= noktaSayisi; i++) {
                   
                    int xRandomlySelected = randomX.nextInt(405) + 25;
                   
                    int yRandomlySelected = randomY.nextInt(405) + 20;
                   
                    System.out.println(i + ". Rastgele secilen nokta " + xRandomlySelected + ", " + yRandomlySelected);

                    coords.add(new Coordinate(xRandomlySelected, yRandomlySelected));
               
                }
               
                DelaunayTriangulationBuilder ucgenBuilder = new DelaunayTriangulationBuilder();
               
                ucgenBuilder.setSites(coords);
               
                Geometry triangles = ucgenBuilder.getTriangles(geometryFactory);
               
                List<Polygon> uretilenUcgenler = new ArrayList<>();
               
                if(triangles instanceof GeometryCollection) {
                   
                    GeometryCollection geometryCollection = (GeometryCollection) triangles;
                   
                    System.out.println("Üretilen üçgen sayısı: " + geometryCollection.getNumGeometries());
                   
                    for(int i = 0; i < geometryCollection.getNumGeometries(); i++) {
                       
                        Polygon ucgen = (Polygon) geometryCollection.getGeometryN(i);
                       
                        uretilenUcgenler.add(ucgen);
                    }
                   
                }

Delaunay triangulation / üçgenleme
Delaunay triangulation / üçgenleme

Nokta sayısını 1000 yaparsak aşağıdaki gibi bir çizimle karşılaşıyoruz.

Delaunay triangulation / üçgenleme noktalar
Delaunay triangulation / üçgenleme noktalar

Voronoi Diagram / Diyagram

Matematikte, bir Voronoi diyagramı, bir düzlemin belirli bir nesne kümesinin her birine yakın bölgelere bölünmesidir. En basitinden, bu nesneler düzlemdeki sonlu sayıda noktadır (tohumlar, siteler veya oluşturucular olarak adlandırılır). Her tohum için, o tohuma diğerlerinden daha yakın olan düzlemin tüm noktalarından oluşan, Voronoi hücresi (Voronoi cell) adı verilen bir bölge vardır. Biyolojiden kimyaya, sağlıktan mühendisliğe çok çeşitli kullanım alanları mevut.

Üçgenleme örneğimize benzer şekilde rastgele 100 noktadan VoronoiDiagramBuilder sınıfını kullanarak Voronoi diyagramı oluşturacağız. Örnek projemizdeki VoronoiDiagramGorsellestirme.java sınıfını çalıştırarak görselleştirebilirsiniz.

                GeometryFactory geometryFactory = new GeometryFactory();

                Random randomX = new Random(System.currentTimeMillis());
                
                Random randomY = new Random(System.currentTimeMillis() + 100);
                
                List<Coordinate> coords = new ArrayList<>();

                int noktaSayisi = 100;

                for(int i = 1; i <= noktaSayisi; i++) {
                    
                    int xRandomlySelected = randomX.nextInt(250) + 65;
                    
                    int yRandomlySelected = randomY.nextInt(250) + 50;
                    
                    System.out.println(i + ". Rastgele secilen nokta " + xRandomlySelected + ", " + yRandomlySelected);

                    coords.add(new Coordinate(xRandomlySelected, yRandomlySelected));
                
                }
                
                VoronoiDiagramBuilder diagramBuilder = new VoronoiDiagramBuilder();
                
                diagramBuilder.setSites(coords);
                
                Geometry triangles = diagramBuilder.getDiagram(geometryFactory);
                
                List<Polygon> uretilenPoligonlar = new ArrayList<>();
                
                if(triangles instanceof GeometryCollection) {
                    
                    GeometryCollection geometryCollection = (GeometryCollection) triangles;
                    
                    System.out.println("Üretilen poligon sayısı: " + geometryCollection.getNumGeometries());
                    
                    for(int i = 0; i < geometryCollection.getNumGeometries(); i++) {
                        
                        Polygon poligon = (Polygon) geometryCollection.getGeometryN(i);
                        
                        uretilenPoligonlar.add(poligon);
                    }
                    
                }

Voronoi Diagram / Diyagram
Voronoi Diagram / Diyagram

Convex Hull - Dışbükey Örtü, Zarf

Convex hull, bir geometrinin tüm noktalarını kapsayan en küçük poligon olarak tanımlanabilir. Örneğimizde, rastgele tanımladığımız 100 noktadan bir MultiPoint nesnesi oluşturacak ve bu nesnenin convexHull() metodu ile zarf poligonunu üreteceğiz. Örnek projemizdeki ConvexHullGorsellestirme.java sınıfını çalıştırarak görselleştirebilirsiniz.

                GeometryFactory geometryFactory = new GeometryFactory();

                Random randomX = new Random(System.currentTimeMillis());
               
                Random randomY = new Random(System.currentTimeMillis() + 100);
               
                List<Coordinate> noktaKoordinatlari = new ArrayList<>();

                int noktaSayisi = 100;
               
                Point[] noktalar = new Point[noktaSayisi];

                for(int i = 1; i <= noktaSayisi; i++) {
                   
                    int xRandomlySelected = randomX.nextInt(250) + 65;
                   
                    int yRandomlySelected = randomY.nextInt(250) + 50;
                   
                    System.out.println(i + ". Rastgele secilen nokta " + xRandomlySelected + ", " + yRandomlySelected);

                    Coordinate coordinate = new Coordinate(xRandomlySelected, yRandomlySelected);
                   
                    noktaKoordinatlari.add(coordinate);
               
                    noktalar[i-1] = geometryFactory.createPoint(coordinate);
                }
               
                MultiPoint multiPoint = geometryFactory.createMultiPoint(noktalar);
                 
                Polygon convexHull = (Polygon) multiPoint.convexHull();

Convex Hull - Zarf
Convex Hull - Zarf

Bu bölümde Delaunay üçgenlemesi ile bir nokta setinden nasıl üçgen üretileceğini, nasıl Voronoi diyagram oluşturulacağını, convex hull poligon geometrisinin nasıl hesaplanacağını gördük. Faydalı olması dileğiyle... 

Önceki Bölümler

  1.  JTS CBS Kütüphanesi Rehberi  1 - Geometri Modeli
  2.  JTS CBS Kütüphanesi Rehberi  2 - Geometrik İlişki Hesaplamaları 
  3.  JTS CBS Kütüphanesi Rehberi  3 - Geometrik Alan Hesaplamaları

Sonraki Bölüm:

JTS CBS Kütüphanesi Rehberi 5 - Quadtree Nedir? Java'da Örnek Kullanım

Java'da Thread ve Semaphore Kullanımı Bayram Harçlığı Örneği

Normal Dede, SemaphoreDede, AtomicDede ve SynchronizedDede torunlarına bayram harçlığını doğru bir şekilde dağıtabilecek mi? Bayram harçlığı...