PHP ile 3 Boyutlu Görüntüler Hazırlayın

0
butch
IBM Türkiye ve Fazlamesai.net işbirliği ile dilimize kazandırılan yeni bir IBM developerWorks makalesi ile karşınızdayız. Diğer makalelere buradan ulaşabilirsiniz.

Makalenin özgün haline bu adresten ulaşabilirsiniz.

PHP ile 3 Boyutlu Görüntüler Hazırlayın


Düzey: Orta

Mike Brittain (mike@mikebrittain.com), Teknoloji Yöneticisi, ID Society

28 Mart 2006

Başlangıçta Web geliştirme amaçlı olarak tasarlanmış bir dil olan PHP, yıllardır dinamik Web sitelerini ve veritabanı uygulamalarını yönetmek için kullanılmıştır. PEAR'ın (PHP Extension and Application Repository) aracılığıyla bu dilde yapılan genişletmeler, geliştiricilere dili yeni ve ilginç yönlere taşıma olanağı tanıdı. PEAR'ın Image_3D paketi, üç boyutlu (3-D) grafiklerin PNG ve SVG gibi modern Web tarayıcılarında giderek daha çok desteklenen iki görüntü biçimi dahil, çeşitli biçimlerde yaratılması için kullanılabilecek nesne odaklı bir arabirimdir. Image_3D paketini nasıl kullanacağınıza ilişkin bilgi edinin, dinamik 3 boyutlu görüntülerin kullanılmasındaki sınırları öğrenin ve 3 boyutlu grafiklerin pratik uygulamalarını görün.

Başlamadan önce

Bu eğitici yazı, 3 boyutlu grafiklerin dinamik olarak oluşturulmasıyla ilgilenen PHP programcıları içindir. Görüntüler sıfırdan yaratılabilir, bir alanda X, Y, ve Z koordinatlarına göre konumlandırılmış ışık kaynaklarından ve nesnelerden oluşturulabilir. 3-D Studio Max kullanmada deneyimli olan programcılar nesnelerin 3DS dosyalarından PHP oluşturmalarına nasıl aktarılacağını anlayacaklardır. Parametrik denklemlerle tanımlanan karmaşık yüzeyler Image_3D kullanılarak kolayca eşlenebilir. Sonuçta, iş uygulamaları ve veri raporları, kolayca hazırlanan pasta grafikler eklenerek zenginleştirilebilir.

Bu eğitici yazı hakkında

Image_3D, 3 boyutlu görüntülerin oluşturulmasında kullanılan nesne odaklı bir arabirimdir. Nesneler ve ışıklar X, Y ve Z koordinatlarına göre, 3 boyutlu alanda konumlandırılır. Sonra görüntüler 2 boyutlu alana dönüştürülür ve PNG, SVG olarak depolanabilir ya da kabuğa (shell) çıkışları alınabilir (ANSI kabuklarında kullanılmak üzere). Paket, küpler, koniler, küreler, metin ve pasta grafikler gibi bir dizi basit 3 boyutlu nesneyi kolayca oluşturmak için kullanılabilir. Ayrıca, 3-D Studio Max'de oluşturulmuş nesneleri içe aktarma ve değiştirme desteği de vardır. 3 boyutlu alanlardan iyi anlayan geliştiriciler, ilginç nesneler oluşturmak için özelleştirilmiş poligram ve yüzey eşlemlerinden yararlanabilirler.

Bu eğitici yazının ilk yarısında, 3 boyutlu görüntü dosyaları oluşturmak için komut satırı PHP komut dosyalarının nasıl kullanılacağı gösterilmektedir. Renkler ve ışıklarla temel bir 3 boyutlu alan oluşturulduktan sonra, her bir eşsiz 3 boyutlu nesne tipinin yanı sıra, çıkış dosyası biçimlerinin her biri de incelenmektedir. İkinci yarıda ise bu temel örneklerin kullanışlı uygulamalara nasıl dönüştürüleceği tartışılır. 3 boyutlu görüntülerin oluşturulmasında işlemci yoğun olarak kullanılır, bu nedenle, dinamik olarak oluşturulmuş görüntüleri Web sunucularınızı çökertmeden Web'e taşımak amacıyla bu sorun için bir çözüm bulmalısınız. Image_3D paketi yalnızca statik görüntü biçimlerini destekler, bu nedenle, 3 boyutlu alanları canlandırmak için basit bir JavaScript çözümü oluşturacaksınız. Sonuçta da, veri raporlarının iş uygulamaları ile bütünleştirilebilen renkli pasta grafikler biçiminde görüntülenmesi için bir PHP sınıfı yazacaksınız.





Sistem gereksinimleri

Devam etmek için aşağıdaki yazılım ve araçlar gereklidir:

PHP V5
Image_3D paketi, PHP V5 nesne ve sınıf sözdizimi kullanılarak yazılır.
Image_3D
PEAR paketinin kurulması gerekir. Genelde, makinenize kök (ya da yönetici) olarak erişiminiz varsa, Image_3D'yi kurmanız kolay olur. Image_3D alfa sürümde olduğu için, PEAR kuruluşu paketin "sabit" olmadığını belirtebilir. Kuruluşu uygulamak için -f seçeneğini kullanın:
pear install -f Image_3D

GD
Bu grafik kitaplığı, PNG dosyalarının çıktısının alınması için gereklidir. Aslına bakılırsa, GD yoksa, Image_3D'den diğer dosya tipleri de oluşturulabilir. PHP V4.3 itibariyle, GD kitaplığının bir sürümü yeni PHP kuruluşlarıyla birlikte gönderilir. Büyük olasılıkla, PHP'yi yeniden derlemekle uğraşmanız gerekmez. Mevcut PHP kuruluşunuzda GD'nin etkinleştirilip etkinleştirilmediğini görmek için phpinfo()'yu kullanabilirsiniz.
Web sunucusu
Bu eğitici yazının ikinci yarısındaki örnekler Web sitesinde kullanılmak üzere oluşturulabilir. Hazırda bir Web sunucunuz yoksa, Apache'nin açık kaynak Web sunucusu ve IBM HTTP Server, kullanabileceğiniz iki uygun seçenektir.
SVG viewer
SVG dosyaları, yerel SVG desteği içeren Mozilla Firefox V1.5 ürününde görüntülenebilir. Internet Explorer kullanıcıları, Adobe SVG eklentisini yükleyerek tarayıcılarına SVG desteği ekleyebilirler.




Önkoşullar

Image_3D'nin arabiriminin tamamı nesne odaklı olduğu için, bu eğitici yazıda, nesnelere ve sınıflara ilişkin en azından temel bilgilere sahip olunduğu varsayılır. Bu eğitici yazının ilk yarısında gösterilen komut satırı PHP örneklerini yürütmek için Linux® kabuk hesabına ya da bir Windows® komut istemine erişim gerekir. Temel düzeyde JavaScript deneyimi de gereklidir.







Alanınızın düzenlenmesi

Çoğu PHP geliştiricisinin 2 boyutlu grafiklerden az da olsa anladığını söylemek yanlış olmaz. Büyük olasılıkla çoğu, Adobe Photoshop, Corel Paint Shop Pro, GIMP ya da başka bir program kullanarak en azından birkaç temel grafik oluşturmuştur. Önce, 3 boyutlu bir alanın ya da dünyanın alışıldık 2 boyutlu tuvalle karşılıklı olarak nasıl ilişkilendirilebileceğini tartışarak başlayalım. Ayrıca, ışıklar, renkler ve dönüşümler gibi 3 boyutlu görüntülerinizi tasarlamanıza yardımı olacak araçları da inceleyeceksiniz.

Başlarken

Sıradan grafik programları, bit eşlemi görüntülerken X ve Y eksenleriyle çalışır. Her bir piksel bu eksenlerde yerleştirilir. Başlangıç noktası (X=0, Y=0), üst sol köşededir. 30, 20 koordinatlarındaki bir piksel, başlangıç noktasının 30 birim (genelde pikseldir) sağında, 20 birim de altındadır.

3 boyutlu alanınızda çalışırken, başlangıç noktası alanın köşesinden çok, merkezini simgeler. Üçüncü eksen, Z, X ve Y eksenlerine karşılıklı olarak diktir. Z ekseninin pozitif yönünü bilgisayarınızın ekranının içine doğru olarak düşünün. Negatif yön, ekrandan uzağa doğru olacaktır. Şekil 1 içinde her bir eksenin yönü gösterilir.


Şekil 1. 3 boyutlu koordinat sistemi
3 boyutlu koordinat sistemi

Koordinat sisteminde 3 boyutlu nesneler oluştururken, her bir nesnenin ya da noktanın başlangıç noktasına olan uzaklığı, negatif ya da pozitif birim olarak ölçülür.





3 boyutlu araç takımınız

3 boyutlu alanınıza yerleştirdiğiniz her bir nesne için (koniler, küreler, vb.) PHP nesneleri oluşturacaksınız. Ayrıca, bu alan içindeki ışık kaynaklarını simgeleyen PHP nesneleri de oluşturacaksınız. Renkli nesneler her bir şekli ya da ışık kaynağını değiştirmekte kullanılır ve bir nesnenin alfa şeffaflığını ayarlamakta da kullanılabilir. Her bir nesnenin boyutunu, dönüşünü, konumunu dönüştürürken ya da hatta alanın bütününü dönüştürürken matris nesneleri oluşturulur.






İlk dünyanızın oluşturulması

İlk görüntünüz, Image_3D ile oluşturulan herhangi bir görüntü için gerekli olan tüm temel öğeleri içerir. Bu örnekten, paketteki tüm temel nesneleri hızla inceleyebilecek doğru alana ve ışığa sahip olacaksınız.

Koniler

Bu ilk örneğin amacı, beyaz bir artalanda ışıklandırılmış koni şeklinde bir nesne yaratılmasıdır. Sonuçta ortaya çıkan alan, 400x400 piksellik bir görüntüye dönüştürülecektir.


Liste 1. 3 boyutlu alanda bir koni oluşturulması
<?php
require_once('Image/3D.php');

// Create the blank three-dimensional space
$world = new Image_3D();
$world->setColor(new Image_3D_Color(255, 255, 255));

// A blue light from the left
$light1 = $world->createLight(-300, 0, -300);
$light1->setColor(new Image_3D_Color(100, 100, 255));

// A green light from the upper-right
$light2 = $world->createLight(300, -300, -300);
$light2->setColor(new Image_3D_Color(100, 255, 100));

// Build the cone object
$cone = $world->createObject('cone', array('detail' => 64));
$cone->setColor(new Image_3D_Color(255, 255, 255));
$cone->transform($world->createMatrix\
('scale', array(70, 220, 70)));
$cone->transform($world->createMatrix('rotation', 
                                      array(-45, -120, -10)));
$cone->transform($world->createMatrix\
('move', array(-50, -30, 10)));

// Render and save the 2-D image
$world->createRenderer('perspectively');
$world->createDriver('gd');
$world->render(400, 400, 'object.png');
?>

Oluşturduğunuz her görüntü, $world olarak adlandıracağınız yeni bir Image_3D nesnesi oluşturularak başlar. Alanın artalan rengi, Image_3D_Color nesnesi oluşturularak ayarlanır. Bu nesnenin yapıcısının üç parametresi, oluşturmak istediğiniz rengin RGB değerleridir.

Alanda iki adet Image_3D_Light nesnesi oluşturursunuz. Mavi bir ışık olan ilkinin, başlangıç noktasının soluna, ekranın düzleminden uzağa yerleştirildiğini düşünün. İkincisi de başlangıç noktasının üst sağ köşesine, yine ekrandan uzağa yerleştirilsin. Bu nesne, yeşil olsun.

Sonra, alana bir koni yerleştirilsin. Bu nesneye atadığınız rengin beyaz olduğuna dikkat edin. Böylece, nesne alana yerleştirdiğiniz iki ışığın rengini alır. Bu yöntem, farklı renklere sahip bir nesnenin karşıt yönlerini vurgulamak için en iyi yöntemdir.

Koniye üç dönüşüm uygulanır. Önce, nesnenin ölçeği yükseltilir. Koni nesnesi, oluşturulurken boyutu atanmayan tek nesnedir. Temelde 1x1x1 boyutlarında bir alanda oluşturulur ve boyutlarının yeniden belirlenmesi gerekir. Sonra, koniyi, ışığı iyi olarak yakalayabilmesi için döndürün. Bu, biraz deneme yanılma sürecidir. Ardından, koniyi taşıyarak görüntünün ortasına yerleştirin.

Komut dosyanızın son adımı, 3 boyutlu alanın 2 boyutluya dönüştürülmesidir. Örneklerin tümünde "perspectively" (perspektif olarak) dönüştürme motoru kullanacaksınız (diğer seçenek, "isometric"dir (eşit ölçekte)). PNG görüntüsünü oluşturacak olan gd çıkış sürücüsü seçilir. Görüntünün boyutunu 400x400 piksel olarak seçin; görüntü, şu dosya adı ile kaydedilecektir: object.png.

Görüntüyü oluşturmak için, komut dosyası komut satırından çalıştırılmalıdır:


php -f build_cone.php

Oluşturulan görüntü dosyası aşağıda gösterildiği gibi görünmelidir:


Şekil 2. Image_3D paketi kullanılarak oluşturulmuş 3 boyutlu koni
Image_3D paketi kullanılarak
oluşturulmuş 3 boyutlu koni




Ayrıntıların denetlenmesi ve gerçekleme (rendering) süresi

Verdiğim örneğin yeterince açıklayıcı olduğunu umarım. Image_3D ile birlikte gönderilen diğer yerleşik nesne tiplerini göstermek için birkaç ek örnekte de aynı alanı, ışıklandırmayı ve gerçeklemeyi kullanacaksınız.

Devam etmeden önce, ilk komut dosyanızla ilgili belirtmemiz gereken iki nokta var. Koni nesnesini örnekle desteklerken, ikinci bağımsız değişken olarak bir dizilimi [array('detail' => 64)] geçirdiniz ; bu dizilim, koniyi oluşturmak için kullanılan çokgenlerin sayısını belirler. Bu çokgenlerin sayısının az olması, görüntünün daha açılı olmasına neden olurken, bu sayının yüksek olması görüntünün yüzeyini düzgünleştirir (bkz. Şekil 3).


Şekil 3. 3 boyutlu konilerde farklı ayrıntı düzeyleri. Gösterilen ayrıntı düzeyleri 8, 16, 32 ve 64'tür
3 boyutlu konilerde farklı ayrıntı
düzeyleri

Ayrıntı düzeyi yükseldikçe, Image_3D'nin görüntüyü oluşturması o kadar uzun sürer. Konilerin oluşturulması oldukça basittir, bu nedenle etkisi korkunç değildir. Kürelere ve daha karmaşık şekillere geçtiğinizde, gerçekleme hızının kolayca denetiminizden çıkabileceğini göreceksiniz.

Görüntünün nasıl oluşturulduğuna ilişkin bilgi sağlayacak olan Image_3D nesnesi için yerleşik bir istatistik yöntemi vardır. Aşağıdaki satırı bir önceki komut satırının sonuna koyun.

echo $world->stats();

Komut dosyası yeniden çalıştırıldığında, Liste 2 içindeki çıkış görüntülenmelidir.


Liste 2. Koni nesnesinin oluşturulması için istatistikler

Image 3D
Objects: 1
Lights: 2
Polygons: 130
Points: 67

Bu basit ayrıntılar bir yana, komutlarınız daha ayrıntılı 3 boyutlu görüntüler oluşturdukça, komut dosyalarınızın yürütülme süresini ölçmek için PEAR::Benchmark paketini kullanmayı düşünebilirsiniz (bkz Kaynaklar).







Işık kaynakları ve renk

Renk ya da ışık olmazsa, 3 boyutlu alanınızda nesneleri göremezsiniz. Şimdi de, yarattığınız nesneleri görmemize olanak sağlayan bu iki önemli öğeyi inceleyelim.

Işıkların açılması

Yukarıdaki örnekteki koninin rengini kırmızıya (255, 0, 0) ayarlayacak ve iki ışık kaynağını kaldıracak olsaydınız, sonuçta ortaya çıkan görüntü, beyaz artalanda siyah bir koni gösterirdi. Üzerinde bir ışık kaynağı parlamadıkça, koninin kırmızı yüzeyi ortaya çıkmaz.

Bu sorunu, en az bir adet ışık kaynağı ekleyerek çözebilirsiniz. Işığın rengini en ortaya çıkaran beyaz ışıktır, bu nedenle ışığın beyaz olması en uygunudur.

Tek bir ışık kaynağı, alanınızdaki nesnenin ya da nesnelerin yalnızca tek bir yanını aydınlatacaktır. Karşı tarafa başka bir ışık kaynağı eklemeniz nesneleri daha da görünür kılar. İki beyaz ışık kullanırsanız, bunlar nesneye pek bir kişilik katmaz, çünkü karşıt açılar yalnızca nesnenin renginin değişik tonlarını yansıtır.

Önceden de tartışıldığı gibi, bunun yerine, bu örneklerde beyaz renkli nesneler oluşturup onları renkli ışıklarla aydınlatacaksınız. Bu, her bir nesnenin özelliklerini ortaya çıkacak olan daha çok ton ve renk özünün kullanılmasına olanak tanır.





Renklerin denetlenmesi

Yukarıdaki örnekte, Image_3D_Color sınıfı kullanarak koni nesnesinin rengini belirlediniz. Yapıcının ilk üç parametresi, istenen rengin RGB değerleridir. Burada gösterilmeyen dördüncü parametre ise, alpha transparency parametresidir. Komut dosyanıza 150 değerini eklediğinizde, kısmen şeffaf bir koni oluşturursunuz.

$cone->setColor(new Image_3D_Color(255, 255, 255, 150));

Şekil 4 içinde, şeffaflığın koni üzerindeki etkisi gösterilir.


Şekil 4. Üst üste yerleştirilmiş iki adet 3 boyutlu koni nesnesi, her ikisinde de 150 değerinde alfa şeffaflık uygulanmıştır
Üst üste yerleştirilmiş iki adet 3
boyutlu koni nesnesi

Krom görüntüsü verin

RGB renklerine uygulanabilen bir etki daha vardır: krom görüntüsü! Koninin rengi olarak standart Image_3D_Color nesnesini sağlamak yerine, yeni bir Image_3D_Color_Metal nesnesi oluşturun (Image/3D/Color/Metal.php'yi eklemeyi unutmayın, diğer sınıflar gibi Image/3D.php tarafından eklenmez). Bkz. Liste 3.


Liste 3. 3 boyutlu nesnelere metal görüntüsünün uygulanması
require_once('Image/3D/Color/Metal.php');

$cone = $world->createObject('cone', array('detail' => 64));
$metal = new Image_3D_Color_Metal(255,255,255);
$metal->setMetal(1.25); 
$cone->setColor($metal);


setMetal() yöntemi, parametre olarak değişiklik gösterir. Biraz deneyim kazanıldığında, 0.5 ve 2.0 arasındaki değerlerin en iyi etkiyi ortaya çıkardığı görülür. 2.0 üzerindeki bir değer, görüntünün tamamen parlamasına neden olur. Koninin renk ve ışığının nasıl etkilendiğini görmek için bu değerle oynayabilirsiniz.







Nesnelerin ve şekillerin değiştirilmesi

Daha önce Adobe Photoshop programındaki dönüştürme aracını kullandıysanız, büyük olasılıkla onun taşıma, ölçekleme, döndürme, çevirme ve çarpıtma öğelerine alışıksınızdır. 3 boyutlu nesnelerin ve alanların transform() yöntemi, bu aracınkine benzer.

Dönüştürme matrisleri

Bu terim sizi korkutmasın. Pratikte, dönüştürme matrisi, aslında yalnızca bir nesnenin taşınmasını, ölçeklenmesini ya da döndürülmesini sağlayan bir denetimdir. Bu, ilk olarak Image_3D_Matrix yaratıp sonra onu bir transform() yöntemine geçirerek elde edilir. Sonuçta, bu pek de zor değildir.

Aşağıda üç örnek verilmiştir (her bir matrisin ikinci parametre olarak üç değerli bir dizilim aldığına dikkat edin):

$obj->transform($world->createMatrix\
('move', array(-50, -30, 10)));
$obj->transform($world->createMatrix\
('scale', array(70, 220, 70)));
$obj->transform($world->createMatrix\
('rotation', array(45, 0, 0)));

'Move' (Taşı) matrisinin dizilim değerleri, X, Y ve Z eksenlerindeki hareketi belirtir. 'Scale' (Ölçeklendir) matrisine uygulanan değerler, aynı üç eksen boyunca ölçekleme derecesini belirtir. 'Rotation' (Döndürme) matrisine ilişkin değerler, her bir eksende 0 - 360 dereceler arasındaki döndürme miktarını belirtir. Şekil 5 içinde nesnenin hangi yöne döndürüldüğü gösterilir (ters yöne döndürmek için eksi değerleri uygulayabilirsiniz).


Şekil 5. X, Y ve Z eksenlerinde döndürme yönleri
Şekil 5. X, Y ve Z eksenlerinde döndürme
yönleri




Dönüştürmeler nerede ve ne zaman uygulanır?

Bu dönüştürmelerin her biri tek bir nesneye ya da 3 boyutlu alanın bütününe uygulanabilir. Yarattığınız ilk örnek görüntünün alanında, bir koninin nasıl döndürülebileceğini, ölçeklendirilebileceğini ve taşınabileceğini gördünüz. Dönüştürme işlemini koni yerine $world nesnesine uygulamış olsaydınız, 3 boyutlu alandaki herşeyi etkilerdi; alandaki tüm nesneler ve ışıklar, büyük bir boşluk olarak, bütünüyle etkilenirdi.

Dönüştürmeler, belirtilen sırayla her bir nesneye uygulanır. Bu size açık gibi görünebilir, ancak önce, nesnelere birer birer ve sonra da alanın bütününe olmak üzere birden çok dönüştürme uyguluyorsanız, dönüştürmelerinizi eklerken sıraya dikkat etmediğinizde beklemediğiniz sonuçlarla karşılaşabilirsiniz.







Ek nesneler

Koninizin ışıklandırılması, renklendirilmesi ve konumlandırılmasına ilişkin pek çok ayrıntıyı tamamladınız. Şimdi de Image_3D'de başka hangi tip nesnelerin yaratılabileceğine dönelim.

Küpler

Koniler gibi, küplerin de yaratılması kolaydır. Küp oluşturmak için yalnızca birkaç çokgen gereklidir, üstelik, boyutları ne olursa olsun, tüm küpler aynı düzeyde ayrıntı içerir. Küp yaratırken, createObject() için ikinci parametre, kübün genişliği, yüksekliği ve derinliğinden oluşan üç değerli bir dizilimdir.

Küp oluştururken, Liste 1 içinde $cone yerine aşağıdaki satırları yazabilirsiniz:

$cube = $world->createObject('cube', array(100, 100, 100));
$cube->setColor(new Image_3D_Color(255, 255, 255));
$cube->transform($world->\
createMatrix('rotation', array(-60,60,40)));

Sonuçta ortaya çıkan görüntü şöyle olur:


Şekil 6. Image_3D paketi kullanılarak oluşturulmuş 3 boyutlu küp
Image_3D paketi kullanılarak oluşturulmuş 3 boyutlu küp




Küreler

Liste 1 içindeki ilk örneğinizi düzelterek devam edersek, koniyi küre ile değiştireceksiniz. Burada, ikinci parametre, kürenin yarıçapını simgeleyen r için bir değer ve nesnenin görece düzgünlüğünü tanımlayan bir tamsayı olan detail (ayrıntı) değerini içeren bir Hash algoritması olacaktır. Detail değeri, 1 kadar küçük olabilir, ama bu durumda nesne, küreden çok buruşturulmuş kağıt topağına benzeyecektir, bu değer arttıkça, nesnenin kalitesi ve gerçekleme süresi de artar. Detail öğesinde en iyi değerler 4, 5 ya da 6'dır. 6'dan daha yüksek bir değer kullanıldığında gerçekleme süresi, saniyelerle değil, ancak dakikalarla ölçülebilecek kadar uzun olur.

$sphere = $world->createObject('sphere', 
 array('r' => 85, 'detail' => 5));  
$sphere->setColor(new Image_3D_Color(255, 255, 255));

Sonuçta ortaya çıkan görüntü şöyle olur:


Şekil 7. Image_3D paketi kullanılarak oluşturulmuş 3 boyutlu küre
Image_3D paketi kullanılarak
oluşturulmuş 3 boyutlu küre

Bu küre oluşturulurken bildirilen istatistikleri (bkz Liste 4), Liste 2 içindeki konide görülenlerle karşılaştırın.


Liste 4. 5 detail değeriyle küre nesnesi oluşturulmasının istatistikleri

Image 3D
Objects: 1
Lights: 2
Polygons: 4096
Points: 2050

Aslında, bu kürenin detail ayarını 6'ya yükseltirseniz, çokgenlerin ve noktaların sayısı dört katına çıkar.





Simit şekli

Wikipedia'ya göre, simit şekli, iki daire şeklinin (S1 x S1) ürünü olarak tanımlanan bir kapalı yüzeydir. Geometri bilgilerinizi unuttuysanız, bildiğiniz bir simidi gözünüzün önüne getirin.

Simit şeklinin nasıl oluşturulduğunu görmek için aşağıdaki kodu 3 boyutlu alanınıza ekleyin.


Liste 5. Simit şekli örneği
$torus = $world->createObject('torus', array('inner_radius' => 90,
                                             'outer_radius' => 120,
                                             'detail_1' => 30,     
                                             'detail_2' => 30));   
$torus->setColor(new Image_3D_Color(255, 255, 255));
$torus->transform($world->createMatrix('Rotation', array(-45,0,-30)));
$torus->transform($world->createMatrix('Move', array(0,-20,0)));

Bir kez daha, createObject()'in ikinci parametresine geçirilen başka bir değer kümeniz var. Bu durumda, inner_radius (iç yarıçap) ve outer_radius (dış yarıçap), simidin iç ve dış yarıçaplarının adlarıdır. Detail_1 (ayrıntı 1) ve detail_2 (ayrıntı 2) öğeleri daha belirsizdir. Bu değerleri ayarlamayı denerseniz, detail_1 öğesinin bantları (halkaya dik olan çizgileri) ve detail_2 öğesinin ise şeritleri (halkanın dış kenarına paralel çizgileri) denetlediğini görürsünüz.

Sonuçta ortaya çıkan görüntü şöyle olur:


Şekil 8. Image_3D paketi kullanılarak oluşturulmuş 3 boyutlu simit şekli
Image_3D paketi kullanılarak oluşturulmuş 3 boyutlu simit şekli




Metin

Image_3D paketi kullanılarak metinler de üç boyutlu olarak gerçeklenebilir. Ancak, metnin stilinin belirlenmesinde pek az seçenek sunulur. Örneğin, yazı tipi seçemezsiniz; pakette yerleşik bulunan tek bir yazı tipinden başka seçeneğiniz yoktur. Yine de, Liste 6 içinde bir metin nesnesinin nasıl yaratılacağı gösterilir.


Liste 6. Metin nesnesi örneği
$text = $world->createObject('text', 'Databases!');
$text->setColor(new Image_3D_Color(255, 255, 255));
$text->transform($world->createMatrix('Scale', array(6, 6, 6)));
$text->transform($world->createMatrix('Rotation', 
  array(-35, 30, -15)));
$text->transform($world->createMatrix('Move', array(-150, 10, 20)));

Önceki örneklerdeki createObject() öğesinin ikinci parametresine geçirilen dizilimin yerine, yalnızca görüntülenecek olan metni sağlamanız yeterlidir.

İnanması zor ama, PHP eğitici yazısının ortasına geldik ve pek çok PHP eğitici yazısının konusu olan aynı anda her yerde bulunan sistemlerden henüz söz edilmedi. Bu henüz adı geçmemiş olan sistemlere ilişkin 3 boyutlu bir gösterim aşağıda verilmiştir:


Şekil 9. Image_3D paketi kullanılarak oluşturulmuş 3 boyutlu metin
Image_3D paketi kullanılarak oluşturulmuş 3 boyutlu metin




3D Studio Max

Şimdiye dek gördüğümüz 3 boyutlu görüntü oluşturmakta kullanılan araçlar temel düzeydeydi, üstelik, sıfırdan görüntü oluşturarak yapabilecekleriniz de sınırlıdır. Önceden yapılmış 3D Studio Max dosyalarını içe aktarma yeteneği (bkz. Liste 7), heyecan verici olasılıklar sunar.


Liste 7. 3D Studio Max dosyası örneği
$obj = $world->createObject('3ds', 'Image_3D.3ds');
$obj->setColor(new Image_3D_Color(255, 255, 255));
$obj->transform($world->createMatrix('Rotation', array(110, 40, 0)));
$obj->transform($world->createMatrix('Scale', array(7, 7, 7)));

Gördüğünüz gibi, nesnenin oluşturulması için, 3D Studio Max dosyasının bulunması yeterli. Image_3D kuruluşu ile biraz ilgilendiyseniz, PEAR paketindeki bazı örnekleri görmüş olabilirsiniz. Yukarıdaki listede içe aktarılan Image_3D.3ds dosyası bu örneklerden alınmıştır. Sonuçta ortaya çıkan görüntü aşağıda gösterilmiştir:


Şekil 10. Image_3D paketi ile içe aktarılmış ve gerçeklenmiş 3D Studio Max dosyası
Image_3D paketi ile içe aktarılmış ve gerçeklenmiş 3D Studio Max dosyası

Elbette, bu sefer işimiz kolaydı, çünkü yukarıdaki dosyada içe aktarılan 3D Studio Max dosyası 200 KB'den küçüktü ve oldukça basit bir dosyaydı. Daha büyük dosyaların açılması sunucunuzu ya da PHP'yi kolayca durma noktasına getirebilir.





Tek bir alanda birden çok nesnenin birleştirilmesi

Şimdiye dek, tek bir 3 boyutlu alandaki nesneleri teker teker gördük. Ama, burada durmamız gerekiyor. Liste 8 içinde, aynı alanda 100'den fazla nesnenin nasıl birleştirileceğinin bir örneği yer alır.

Daha önce de olduğu gibi, bu kod Liste 1 içindeki, $cone nesnesini tanımlayan satırların yerine geçer.


Liste 8. Küre nesnelerinden birleştirilmiş bir kübün oluşturulması
for ($x=0; $x < 5; $x++) {
    for ($y=0; $y < 5; $y++) {
        for ($z=0; $z < 5; $z++) {
            $sphere = $world->createObject('sphere', 
                                  array('r' => 25, 'detail' => 4));
            $sphere->setColor(new Image_3D_Color(255, 255, 255));
            $sphere->transform($world->createMatrix('Move', 
                                  array($x * 75, $y * 75, $z * 75)));
            $sphere->transform($world->createMatrix('Rotation', 
                                  array(45, 30, 15)));
        }
    }
}

$world->transform($world->createMatrix('Move', array(-225, -100, 0)));

Liste 8, $x, $y ve $z'yi 0-4'ten artıran üç döngü tanımlar. Orta döngü içinde, tek bir küre nesnesi yaratılır. Bir move dönüştürmesi kullanarak, her bir yeni küre, başlangıç noktasına göre X, Y ve Z yönlerinde konumlandırılır. Taşındıktan sonra, her bir küre başlangıç noktasının çevresinde döndürülür.

Kürelerin her biri yaratıldıktan ve üç döngünün tümü de tamamlandıktan sonra, $world nesnesinin bütünü, görüntünün sınırları içinde kürelerin ortalanacağı biçimde kaydırılır.

Bu örnekte 125 kürenin oluşturulduğuna dikkat edin. Detail ayarı 4 değerinde olan tek bir bir küre oluşturmakta zorlandıysanız, 124 tane daha küre oluşturmanın ne kadar güç olabileceğini tahmin edebilirsiniz. Detail değeri 4 ya da 5 olduğunda nesne gerçekten çok güzel görünür, ama herşeyin düzgün olarak çalıştığından emin oluncaya dek, bu ayarı 1 ya da 2'ye çekmeniz akıllıca olur.

Şekil 1 içinde gösterilen sonuçta ortaya çıkan görüntünün sadece küpler ve konilerden çok daha heyecan verici olduğunu kabul edersiniz.


Şekil 11. Küp şekilli bir matris yaratmak için düzenlenen 125 küre
Küp şekilli bir matris yaratmak için düzenlenen 125 küre



Özel biçimler ve yüzeyler

Image_3D içinde daha özel nesnelerin oluşturulmasına olanak tanıyan iki nesne vardır: çokgenler ve eşlemler

Çokgenlerin oluşturulması

3 boyutlu bir biçimin çok boyutlu koordinatlarda tasarlanabileceğini varsayarsak, bu koordinatları bir araya getirerek 3 boyutlu bir nesnenin kenarlarını oluşturabilirsiniz. Dikkatli bir hesaplamayla, noktalar ve çokgenler kullanarak sıfırdan küpler, koniler ya da küreler oluşturabilirsiniz. Ama bu nesneleri oluşturmanın daha kolay yolları da vardır.

Bunun yerine, üçüncü boyutu, yani derinliği olan üç noktalı bir yıldız oluşturalım. Yıldızın bir ön, bir de arka yüzü olacaktır, sonuçta bunlar, dış kenarları tanımlayan aynı koordinat noktalarına sahip olacaktır. Altı noktaya gerek vardır -- üçü yıldızın noktaları için, üçü de kenarları belirlemek için kullanılır. İşleri kolaylaştırmak için, Z=0 koordinatlarında yatan noktalar ön yüzünüz olsun. Arka yüz, ön yüze göre sabit bir uzaklıkta, 60 değer ötede olacaktır. Böylece, tüm dış noktalar aynı X ve Y koordinatlarına sahip olacaktır, ama Z koordinatı 60 olarak değiştirilecektir.

Üç kenar, yıldızın her bir dış noktasını birleştirecek biçimde eşlenir.

Liste 9'un çoğunluğu, bu nesnenin oluşturulması için birbirine bağlanması gereken noktaların yerleştirilmesiyle ilgilidir. Aşağıdaki foreach döngüleri, sonuçta ortaya çıkacak olan çokgen nesnesini oluşturmakta kullanılacak olan Image_3D_Point nesnelerini oluşturmak için kullanılır.

Son satır $world nesnesinin bütününü döndürür, böylece yıldızın kenarını görebilirsiniz. Alanı döndürmezseniz, yıldızın ön yüzünü yalnızca iki boyutlu olarak görürsünüz.


Liste 9. Üç noktalı yıldız oluşturulması
$polygons = array();

// Front face
$polygons[] = array(
                array(0, -120, 0), array(-18, -12, 0), 
                array(-86, 48, 0), array(0, 18, 0), 
                array(86, 48, 0),  array(18, -12, 0)
              );

// Back face
$polygons[] = array(
                array(0, -120, 60), array(-18, -12, 60), 
                array(-86, 48, 60), array(0, 18, 60), 
                array(86, 48, 60),  array(18, -12, 60)
              );

// 3 Sides
$polygons[] = array(
                array(0, -120, 0),  array(-18, -12, 0), 
                array(-86, 48, 0),  array(-86, 48, 60), 
                array(-18, -12, 60),array(0, -120, 60)
              );
$polygons[] = array(
                array(-86, 48, 0), array(0, 18, 0), 
                array(86, 48, 0),  array(86, 48, 60), 
                array(0, 18, 60),  array(-86, 48, 60)
              );
$polygons[] = array(
                array(86, 48, 0),  array(18, -12, 0), 
                array(0, -120, 0), array(0, -120, 60), 
                array(18, -12, 60),array(86, 48, 60)
              );

foreach ($polygons as $poly) {
    $points = array();
    foreach ($poly as $set) {
        $points[] = new Image_3D_Point($set[0], $set[1], $set[2]);
    }
    $p = $world->createObject('polygon', $points);
    $p->setColor(new Image_3D_Color(255, 255, 255));
}

$world->transform($world->createMatrix('Rotation', 
                                       array(0, -25, -15)));

Bu liste, Şekil 12 içinde gösterilen görüntüyü oluşturur.


Şekil 12. Image_3D paketi kullanılarak oluşturulmuş özel bir çokgen
Image_3D paketi kullanılarak oluşturulmuş özel bir çokgen




3 boyutlu yüzeylerin eşlenmesi

Sıradaki iki örnekte ilginç bazı şekiller oluşturulur, ama biraz Calculus bilgisi de devreye girer. Hiç Calculus dersi almadıysanız ya da bu konudaki bilgilerinizi unuttuysanız, bu yazıda, körelmiş becerilerinizi bilemeye çalışmayacağız. Ancak, aşağıdaki modellerde neler olup bittiğine ilişkin temel bir fikir vermeye çalışacağız.

Mathematica yazılımıyla yüzeyleri ve kıvrımları tasarlama deneyiminiz varsa, sıradaki iki örnek size tanıdık gelecektir.





Helezon

Bu iki listenin ilki yükselen bir sarmaldır. Yüzeydeki her bir noktanın, aşağıdaki parametrik fonksiyondan türeyen X, Y ve Z koordinatları vardır:

f[s,t] = {s * cos(2 ? t), s* sin(2 ? t), t}

Bu yüzeyi yaratmak için, önce alanınızda yeni bir "eşlem" nesnesi yaratacaksınız.

$map = $world->createObject('map');

Eşlem, yukarıdaki özel çokgende gördüğünüz gibi 3 boyutlu bir yüzey oluşturmak için Image_3D_Point nesnelerinin dizilimini alır. Bu noktaların her biri yukarıdaki işlevinize göre tanımlanabilir:

new Image_3D_Point( ($s * cos(2 * pi() * $t)), 
  ($s * sin(2 * pi() * $t)), 
  ($t) );

s ve t parametrelerini sırasıyla 0-1 ve 0-6 aralıklarında değiştireceksiniz. Yüzeye uygun bir boyut vermek için, her bir koordinatı $scale ayarına atayacağınız istediğiniz bir değerle çarpacaksınız.

Liste 10 içinde, eşlem nesnesinin nasıl oluşturulduğu gösterilir ve diğer örneklerde de olduğu gibi, nesnenin son halinin rengini, döndürmesini ve konumunu siz belirlersiniz.


Liste 10. Parametreleri belirlenmiş bir sarmal yüzey
$map = $world->createObject('map');

$scale  = 120;
$detail = 30;
$levels = 6;
$increment  = 1 / $detail;

for ($s = 0; $s <= 1; $s += $increment) {
        $row = array();
        for ($t = 0; $t <= $levels; $t += $increment) {
             $row[] = new Image_3D_Point( 
                          $scale * ($s * cos(2 * pi() * $t)),   // x
                          $scale * ($s * sin(2 * pi() * $t)),   // y
                          $scale * ($t)                         // z
                        );
        }
        $map->addRow($row);
}

$map->setColor(new Image_3D_Color(255, 255, 255));
$map->transform($world->createMatrix('Rotation', array(-50, 0, 15)));
$map->transform($world->createMatrix('Move', array(50, -220, 0)));

Şekil 13 içinde sonuçta ortaya çıkan görüntü gösterilir. Helezonun ayrıntı, ölçek ve yükseklik düzeyleri $scale, $detail ve $levels değişkenleriyle belirlenir.


Şekil 13. Image_3D paketinin eşlem nesnesi kullanılarak oluşturulmuş helezon
Image_3D paketinin eşlem nesnesi kullanılarak
oluşturulmuş helezon




Ortası delik kek kalıbı şekli

Stokes teoreminin bir uygulaması olan ikinci yüzey integraliniz de ilginç bir sonuç verir. Bu yüzeyi, Z ile ifade edilen yüksekliği değişken ve X ve Y düzlemlerinin başlangıç noktasından her yöne yayılan bir sinüs dalgasının ürünü olarak düşünebilirsiniz.

Calculus terimlerini bir yana bırakırsak, bu şeklin ortası delik bir kek kalıbına benzediğini söyleyebiliriz.

Bu alan, aşağıdaki parametrik işleve göre tanımlanacaktır:

f[r,t] = {r * cos(t), r * sin(t), sin(4 ? r)}

Yine, bu yüzey için eşlem nesnesine eklenecek noktaları işaretleyeceksiniz. Her nokta Liste 11'de tanımlanır.


Liste 11. Noktaların tanımlanması
new Image_3D_Point( ($r * cos($t)), 
                    ($r * sin($t)), 
                    (sin(4 * pi() * $r)) 
                  );

Her bir noktayı, düzgün bir yüzey oluşturmak üzere r ve t parametrelerini değiştiren iki döngü içine saracaksınız. Liste 12'de gösterildiği gibi, her X-, Y- ve Z koordinatı bir $scale değeriyle çarpılacaktır.


Liste 12. 3 boyutlu ortası delik bir kek kalıbı şekli
$map = $world->createObject('map');

$scale  = 130;
$detail = 35;
$increment  = 1 / $detail;

for ($r = 0; $r <= 1; $r += $increment) {
    $row = array();
    for ($t = 0; $t <= (2 * pi()); $t += $increment) {
         $row[] = new Image_3D_Point( $scale * ($r * cos($t)), 
                                       $scale * ($r * sin($t)), 
                                       $scale * (sin(4 * pi() * $r)) 
                                      );
    }
    $map->addRow($row);
}

$map->setColor(new Image_3D_Color(255, 255, 255));
$map->transform($world->createMatrix('Rotation', array(-45, 0, -15)));

Sonuçta ortaya çıkan görüntü şöyle olur:


Şekil 14. Image_3D paketindeki eşlem nesnesi kullanılarak geliştirilen parametrik işlevden oluşan 3 boyutlu yüzey
Image_3D paketindeki eşlem nesnesi kullanılarak geliştirilen parametrik işlevden oluşan 3 boyutlu yüzey





Ek çıktı sürücüleri

Şimdiye kadar yarattığınız tüm görüntüler GD sürücüsünü kullanıyordu. Bu sürücünün PNG görüntüleri oluşturduğunu gördünüz. Ancak kullanabileceğiniz dört ek sürücü daha vardır: SVG, SVGRotate, ZBuffer ve ASCII.

SVG

SVG (Scalable Vector Graphics; Ölçeklenebilir Vektör Grafiği) dosya biçimi, 2 boyutlu görüntüler oluşturan vektörlerin bir XML tanımıdır. W3C, bu biçimi 2001 yılında standartlaştırmıştır, ancak bu biçimin Web üzerindeki kullanımı, SVG dosyalarını görüntüleyebilen tarayıcıların kullanılabilir hale gelmesiyle engellenmiştir. Şu anda en uygun seçenekler SVG için yerleşik destek içeren Firefox V1.5 ve Adobe SVG eklentisine sahip Internet Explorer ürünleridir.

Image_3D'den SVG görüntüleri oluşturmak oldukça basittir. Yapılması gereken yalnızca Liste 1'deki son iki kod satırını aşağıdaki gibi değiştirmektir:

$world->createDriver('svg');
$world->render(400, 400, 'object.svg');

Sonuçta ortaya çıkan görüntü dosyası ilk yarattığınız koniye çok benzer olmalıdır.

SVG dosyalarının heyecan verici bir yönü, görüntüyü tanımlayan XML ağacının, JavaScript ve DOM ayrıştırma yordamları kullanılarak işlenebilmesidir. Görüntülerin, Web sayfalarını işlemek üzere dHTML kullanır gibi işlendiğini düşünün. SVGRotate sürücüsü, yalnızca bu amaçla gerekli olan komut dosyasını içeren bir SVG dosyası oluşturur.

Çıktı sürücüsünün değiştirilmesi yine son iki kod satırının değiştirilmesiyle kolay bir şekilde gerçekleştirilebilir:

$world->createDriver('svgrotate');
$world->render(400, 400, 'object.svg');

Sonuçta ortaya çıkan dosya, SVG biçimini tanıyan bir tarayıcıda görüntülendiğinde, koniyi gerçek zamanlı olarak döndürmek ve ölçeklemek için kullanılabilecek yerleşik denetimleri içerir. Görüntünün bir ekran görüntüsü aşağıda gösterilmiştir.


Şekil 15. SVGRotate sürücüsü görüntüyü gerçek zamanlı olarak işlemek için kullanılabilecek denetimleri ve komutları içerir.
SVGRotate sürücüsü görüntüyü gerçek zamanlı olarak işlemek için kullanılabilecek denetimleri ve komutları içerir.

Komut dosyası içeren SVG dosyaları sağlanan desteğin sınırlı olduğunu göz önünde bulundurun. Sonuçta ortaya çıkan dosya Adobe SVG eklentisi olan bir Internet Explorer'da çalışmasına karşın Firefox'ta düzgün görüntülenmemiştir.





ZBuffer

3 boyutlu alanların 2 boyutlu bir görüntüye dönüştürülmesi için hangi nesnelerin üst üste gelip diğerlerini gizlediğini belirleyebilen özel bir algoritma gerekir. 3 boyutlu modellemede, nesnelerin 2 boyutlu bir alanda görünebilirliğinin yönetilmesine Z-buffering (Z-arabelleği) adı verilir.

Şimdiye kadar size verilen örneklerin hiçbirinde diğer nesnelerin üzerine gelen nesnelerle ilgili sorunlar yoktu. Böyle bir sorunla karşılaşırsanız, en uygun seçenek çıktı sürücünüzü GD'den ZBuffer'a değiştirmektir. ZBuffer sürücüsü bir PNG görüntüsü oluşturmak üzere hala GD'yi kullanır, ancak 2 boyutlu bir bit eşlem üzerinde çizili olduklarından 3 boyutlu nesneleri daha iyi yönetebilir.

Liste 13'teki kodu kullanarak, nesnelerin Z-buffering işleminde özellikle bir çakışmaya neden olacak, aynı alanı kaplayan iki nesne yaratacaksınız. Kürenin alfa şeffaflık değeri 150 olarak verilmiştir; böylece küreyi ortasından ikiye kesen düzlemi görebilirsiniz.


Liste 13. Küreyi kesen dört kenarlı bir düzlem
$sphere = $world->createObject('sphere', 
                               array('r' => 85, 'detail' => 4));
$sphere->setColor(new Image_3D_Color(255, 255, 255, 150));

$plane = $world->createObject('polygon', array( 
                                new Image_3D_Point(-120, 0, -120),
                                new Image_3D_Point(-120, 0,  120),
                                new Image_3D_Point( 120, 0,  120),
                                new Image_3D_Point( 120, 0, -120)
                              ) );
$plane->setColor(new Image_3D_Color(255, 255, 255));
$plane->transform($world->createMatrix('Rotation', array(15,15,-10)));

Bu nesneyi GD sürücüsünü kullanarak oluşturursanız, aşağıda gösterildiği gibi, küre düzlemin önünde duruyormuş gibi görünür.


Şekil 16. GD sürücüsü kullanılarak ayrı ayrı oluşturulmuş üst üste gelen iki adet 3 boyutlu nesne
GD sürücüsü kullanılarak ayrı ayrı oluşturulmuş üst üste gelen iki adet 3 boyutlu nesne

Ancak, yarattığınız düzlemin koordinatlarından, bunun kürenin içinden geçip küreyi kesmesi gerektiğini bilirsiniz. Sürücünün ZBuffer olarak değiştirilmesi bu sorunu çözer ve aşağıda gösterilen PNG dosyası ortaya çıkar.


Şekil 17. ZBuffer sürücüsü uygulanarak çözülen, üst üste gelmiş iki adet 3 boyutlu nesne arasındaki ZBuffer çakışmaları
ZBuffer sürücüsü uygulanarak çözülen, üst üste gelmiş iki adet 3 boyutlu nesne arasındaki ZBuffer çakışmaları




ASCII

Örneklerinizde ASCII sürücüsü bulunmamaktadır, ancak bu sürücünün amacı renkli bir ANSI uçbiriminde görüntülenecek görüntüler yaratılmasına olanak vermektir. Windows® kurulu bir PC'de çalışıyorsanız, bu sürücüden elde edilen çıktı büyük olasılıkla sizin için pek yararlı olamayacaktır.






Pratik örneklere geçiş

Şimdiye kadar gördüğünüz örnekler bu paketin PHP'de 3 boyutlu görüntüler oluşturma yeteneklerini göstermiştir. Web sayfalarını yönetmek için icat edilen bu dilin bu kadar ayrıntılı görüntü dosyaları oluşturmak üzere kullanılabileceğini kim tahmin edebilirdi? Bu oldukça iyi bir olanak, ancak 3 boyutlu sihirbaz ya da hesap meraklısı değilseniz bu size sıkıcı gelmiş olabilir. Basit nesneleri ve komut satırı komut dosyalarını alıp nasıl biraz daha ilginç örnekler oluşturabileceğinize bakalım.

3 boyutlu görüntülerin canlandırılması

GD grafik kitaplığı, GIF görüntülerini destekleme konusunda parçalı bir geçmişe sahiptir. Lisanslama sorunları nedeniyle, V1.6 yayın düzeyinden sonra GIF desteği GD'den kaldırıldı, ancak V2.0.28 yayın düzeyiyle yeniden kondu. Her durumda, Image_3D, canlandırmalı GIF'lerin dışa aktarılmasına izin vermez ve PNG dosyaları canlandırmayı desteklemez.

Döngülü bir canlandırma yürütecek tek bir dosya yaratmak yerine, bir "flip-book" etkisi yaratmak için birden çok dosyayı nasıl kullanabileceğinize bakalım. Örneği, 30 ayrı dosya oluşturarak kürelerden oluşan bir küp ile genişleteceksiniz. Arka arkaya görüntülendiğinde, ortaya çıkan canlandırma, kübü iki eksen üzerinde döner bir şekilde gösterecek.

Görüntülerin her birini oluşturmak için tek bir komut dosyası kullanacaksınız: $cycles. Döngü için en dışta, her dosya için değişecek ancak ayrı ayrı dosyalar içindeki her küreye uygulanacak üç dönüş değeri belirleyeceksiniz. Amacınız canlandırmanın düzgün bir döngü içinde yürümesi olacağı için dönüşün 360 derecelik hareketlerle yürümesi gerekecek.

Y ekseni dönüşü için sabit bir dönüş değeri (30) ile başlayın. Buradan, sırada oluşturmakta olduğunuz dosyaya göre 360 derecelik bir döngü ile artış ekleyebilirsiniz. 360 derecelik bütün halindeki artışları gerçekleştirmek için modulus işleci kullanılır; bu durumda 375 derecelik bir dönüş 15 derece azaltılarak dönüşün ilk çevrimi içinde kalır.

$rot_y = (30 + (int) (360 / $cycles * $i)) % 360;

Bu görüntüleri oluşturmanın en zor kısmı anlatıldı. Kodun geri kalanı size tanıdık gelmeli. Bir $world nesnesi yaratırsınız ve buna iki ışık kaynağı verirsiniz. Üç döngü kullanarak, kürelerden oluşan kübü yaratırsınız.

Oluşturduğunuz ilk küre kübü, boyut başına beş küp içeriyordu ve bunun için 125 adet 3 boyutlu nesne yaratılması gerekiyordu. Ayrıca bu görüntülerden 30 adet yaratıyorsunuz ve bu, 3.000'den fazla küre anlamına geliyor. Aşağıdaki kodda, kenar başına dört küre gelecek şekilde bir ölçek küçültmesi gerçekleştirdiniz ve her kürenin ayrıntı düzeyini üçe indirdiniz (bkz. Liste 14).


Liste 14. 30 adet "flip-book" sayfası oluşturulması
<?php
require_once('Image/3D.php');

$cycles = 30;
for ($i=0; $i < $cycles; $i++) {

    $rot_x = 45;
    $rot_y = (30 + (int) (360 / $cycles * $i)) % 360;
    $rot_z = (15 + (int) (360 / $cycles * $i)) % 360;

    $world = new Image_3D();
    $world->setColor(new Image_3D_Color(255, 255, 255));

    $light1 = $world->createLight(-500, 0, -500);
    $light1->setColor(new Image_3D_Color(255, 255, 0));

    $light2 = $world->createLight(300, -300, -1000);
    $light2->setColor(new Image_3D_Color(255, 162, 0));

    for ($x=0; $x < 4; $x++) {
        for ($y=0; $y < 4; $y++) {
            for ($z=0; $z < 4; $z++) {
                $sphere = $world->createObject('sphere', 
                            array('r' => 25, 'detail' => 3));

                $sphere->setColor(new Image_3D_Color(255, 255, 255));

                $sphere->transform($world->createMatrix('Move', 
                            array(($x * 75) + 50, $y * 75, $z * 75)));

                $sphere->transform($world->createMatrix('Rotation',     
                            array($rot_x, $rot_y, $rot_z)));
            }
        }
    }

    $world->transform($world->createMatrix('Move', 
                                           array(-225, -100, 0)));

    $world->createRenderer('perspectively');
    $world->createDriver('gd');
    $world->render(800, 800, 'animated_png/anim' . ($i+1) . '.png');
}
?>

Komut satırından kodu çalıştırın, sonra gidip kendinize bir bardak kahve yapın. Bu işlem biraz zaman alacaktır.

Bir sonraki adım tüm bu görüntülerin bir birine tutturulmasıdır. Bunu ilk görüntüyü bir HTML sayfasında görüntüleyerek ve görüntü kümesi içinde bir görüntüden diğerine geçmek için JavaScript'i kullanarak yapacaksınız. Sayfa üzerindeki görüntüler arasında geçiş yapılması, Image nesnesinin src özelliği değiştirilerek gerçekleştirilen standart bir tekniktir. Aşağıdaki JavaScript örneğiniz, "flip-book" için gerekli görüntü dizilimini hazırlar, görüntüyü değiştirmek için bir işlev tanımlar ve setInterval() zamanlayıcısını kullanarak animate() işlevini yürütür.


Liste 15. "Flip-book" yaratmak üzere kullanılan HTML ve JavaScript
<html>
<head>
<title>Animated PNG</title>
</head>
<body>

<script type="text/javascript">
var imageset = new Object();
imageset.seconds = 0.1;
imageset.imgTag = "animation";
imageset.images = new Array();
for ($i=1; $i <= 30; $i++) {
    imageset.images.push('animation_01/anim' + $i + '.png');
}

function animate(animObj) {
    if (!animObj.index) {
         animObj.index = 0;
    }

    animObj.index++;
    if (animObj.index >= animObj.images.length) {
         animObj.index = 0;
    }

    document.images[ animObj.imgTag ].src = 
                                   animObj.images[ animObj.index ];
}

document.write('<img src="' 
              + imageset.images[0] 
              + '" name="animation" />');

setInterval("animate(imageset);", imageset.seconds * 1000);
</script>

</body>
</html>

Ortaya çıkan canlandırma statik 3 boyutlu görüntülerinizi canlandırır.





Dinamik görüntülerin Web üzerinde görüntülenmesi

3 boyutlu görüntüler oluşturmanın zorluklarından biri, bunların yaratılması için çok fazla zaman, bellek ve işlemci çevrimi gerekmesi ve bu nedenle de bunların Web sitelerinde kullanım için uygun olmamasıdır. Bu sorunları çözmek için neler yapabilirsiniz?

Öncelikle, bu komut dosyalarını bir Web tarayıcısı üzerinden çalıştırmaya karar verirseniz, Image_3D paketinin görüntü dosyasını oluşturmayı bitirmesini beklerken sunucu bağlantısının zamanaşımına uğradığını görebilirsiniz. Komut dosyanızın en üstüne yakın bir yere aşağıdaki satırı ekleyerek PHP'nin maksimum yürütme süresini devre dışı bırakabilirsiniz.

set_time_limit(0);

complex3-D görüntülerinin oluşturulması PHP'de çok fazla bellek harcayabilir. Komut satırından çalıştırma sorun olmayabilir ancak bu komut dosyalarını bir kez Web üzerinden çalıştırdığınızda yine sunucunuzun bağlantıyı kapattığını görebilirsiniz. PHP komut dosyalarınıza yeterince bellek ayırdığınızdan emin olun. Genellikle, php.ini dosyasında ya da yerel bir .htaccess dosyasında memory_limit değerini değiştirebilirsiniz.

Tüm örneklerde, Image_3D, görüntüler yaratır ve bunları bir dosyaya kaydeder. Ancak dosyanın adı aşağıdaki iki PHP çıktı akışından biriyle değiştirilebilir:

  • php://stdout
  • php://output

Bir Windows sunucusunda test ettiğinizde bu yöntem başarısız olur, ancak GD sürümü de çıktı akışlarını düzgün desteklemiyor olabilir. Bu nedenle, bu yöntemle ilgili bir sorununuz varsa, görüntüyü dosyaya kaydetmeyi, dosyayı açıp içeriği çıktı arabelleğine aktarmayı deneyin. Bu en etkili çözüm gibi görünmese de, 3 boyutlu görüntüler oluşturduğunuzu unutmayın. Dosya giriş/çıkışı büyük olasılıkla bu komut dosyası için bir engel oluşturmayacaktır.

PHP'den bir görüntü dosyası oluştururken sunucunun yanıt üstbilgileri için her zaman uygun içerik tipini eklemeyi unutmayın. PNG görüntülerinde, aşağıda gösterildiği için image/png değerini kullanın:

header("Content-type: image/png");





Dinamik dosyaların önbelleğe alınması

Anında 3 boyutlu görüntüler oluşturma fikiri iyi olsa da, bir saat içinde komut dosyasında birkaç isabetten daha fazlasını yakalarsanız Web sunucunuzda büyük bir performans gerilemesi yaşayabilirsiniz. Bunu nasıl önleyebileceğinize ilişkin bir örneğin üzerinden geçelim.

3 boyutlu küre görüntüleri yaratan bir komut dosyanız olduğunu düşünün. Bu komut dosyasının adı spheres.php olsun. Bu dosya yalnızca tek boyutlu ve tek renkli bir küre yaratırsa bu pek yararlı olmayabilir. Komut dosyasını her çağırdığınızda komut dosyasına iki parametre geçirdiğinizi düşünün: Bu parametrelerden biri küre nesnesini yaratmak için kullanılacak ve r ile gösterilecek olan radius (yarıçap) parametresi olacak. İkinci parametre olan color (renk) parametresi ise, kürenin rengini vermek için dokuz basamaklı bir RGB değeri olacak. Aşağıdaki örnekte bu komut dosyasını bir Web sayfasından nasıl çağırabileceğiniz gösterilmektedir:

<img src="sphere.php?radius=20&color=255000000" alt="Red ball" />

Küreyi oluşturmak için 5 ya da üzeri bir ayrıntı düzeyi kullandığınızı varsayarsak, büyük olasılıkla, Web sayfanıza gelen her ziyaretçi için görüntünün yeniden yaratılmasını engellemek isteyeceksiniz.

Kullanacağınız yaklaşım, yarattığınız her görüntü için, dinamik görüntüyü yaratmak üzere kullanılan iki parametreyi içeren biçimlendirilmiş bir dosya adı yaratmak olacaktır: örneğin sphere_20_255000000.png.

spheres.php komut dosyası her çağrıldığında, ilk önce isteği karşılayacak eşleşen bir görüntü dosyası olup olmadığına bakacaksınız. Böyle bir dosya varsa, dosyayı açın ve içeriği çıktı akışına aktarın. Böyle bir dosya yoksa, Image_3D nesnesini oluşturun, yeni görüntü dosyasını kaydedin, daha sonra dosyayı açıp içeriği çıktı akışına aktarın. İlk ziyaretçinin görüntüyü görmek için kısa bir süre beklemesi gerekebilir ancak sonraki ziyaretçiler önbelleğe alınmış olan versiyonu alacaklardır.

Ve sistem yöneticiniz sizi sevecektir!





Pasta dilimi oluşturulması

Sonunda, doğrudan işinizde ve veritabanı uygulamalarınızda kullanılabilecek gerçekten düzgün bir Image_3D örneği göreceğiniz bir noktadasınız.

Image_3D, henüz anlatılmamış olan bir nesne tipini daha destekler: pasta grafik. Hemen konuya girelim ve üç boyutlu bir pasta diliminin nasıl görüneceğine bakalım. Her bir pasta dilimi farklı bir renkte olacak, bu nedenle beyaz nesneler ve renkli ışıklar yerine beyaz ışık ve renkli nesneler kullanacaksınız.

Liste 1'deki standart ortamınızda başlayın, ancak iki ışık kaynağını tek bir beyaz ışıkla değiştirin (bkz. Liste 16).


Liste 16. 45 derecelik mavi bir pasta grafik dilimi
$light = $world->createLight(0, 1000, 1000);
$light->setColor(new Image_3D_Color(255, 255, 255));

$pie = $world->createObject('pie', array('start' => 0, 
                                         'end' => 45, 
                                         'detail' => 20, 
                                         'outside' => 150));
$pie->setColor(new Image_3D_Color(0, 0, 255));

$world->transform($world->createMatrix('Scale', array(1, 1, 10)));
$world->transform($world->createMatrix('Rotation', array(-60, 0, 0)));

Pasta nesnesinin yaratılması için, createObject() yöntemine geçirilen array parametrenizde dört giriş gerekir. Start ve end, dilimin başlangıç ve bitiş derecesi ölçülerini gösterir. Bunlar 0 dereceden başlayarak ölçülür. Pastayı bir saat gibi düşünürsek, 0 derece saat 3 konumunda yer alır ve açı ölçümü saat yönünde yapılır. Detail değeri, nesne için bir düzgünlük düzeyi sağlar, outside ise dairesel pastanın göreli boyutunu gösterir.

Bu nesne üzerinde iki dönüşüm kullanırsınız. Ölçek dönüşümü, 10 değerine sahip bir Z-ekseni boyutu kullanarak, her bir dilime bir derinlik hissi vermek için kullanılır. X-eksenine uygulanan dönüş, pastayı iş grafiklerinde görülen tanıdık yönlendirmeye doğru eğer (Şekil 18).


Şekil 18. Tek bir pasta nesnesi
Tek bir pasta nesnesi

Pastaya dilim eklendikçe, bunların beklenmedik bir şekilde üst üste geldiklerini görebilirsiniz. GD sürücüsünü ZBuffer ile değiştirerek bu sorunu kolayca çözebilirsiniz.

Bir e-ticaret Web sitesi için müşteri kayıtlarını saklamak üzere Apache Derby veritabanını kullandığınızı varsayalım. Her bir müşteri kaydı, her bir posta adresinin ilini içerecektir. Hızlı bir SQL sorgusu, Liste 17'de gösterildiği gibi her bir ilde kaç müşterinin yaşadığını ortaya çıkaracaktır.


Liste 17. Farklı illerdeki müşteri kayıtlarının sayısının seçilmesi
SELECT COUNT( * ) AS customers, state
FROM customers
GROUP BY state
ORDER BY customers DESC





Sınıf arabirimi tasarlanması

SQL sonuç kümesini bir HTML tablosuna dönüştürecek biçimlemeyi kolayca oluşturabilirsiniz. Bu tabloya eşlik edecek güzel bir pasta grafik ekleyelim. Bu örnekte, programınızın 3 boyutlu grafiği nasıl oluşturmasını istediğinize ilişkin bir sınıf arabirimi tasarlayarak başlayalım. Her bir dilim bir bütünün yüzdesi olarak tanımlanacak. Dilimleri HTML tablosundaki verilerle doğrudan ilişkilendirmek istemeniz durumunda, her bir dilimin rengini belirleyebilirsiniz. Son olarak, isteğe bağlı üçüncü bir parametre ana pastadan belirli dilimleri çekerek çağırmanıza olanak verir ($slice->explode); bkz. Liste 18.


Liste 18. 3 boyutlu bir görüntü oluşturmak için bir pasta grafik sınıfı kullanılması
<?php
require_once 'pie_chart_class.php';

$chart = new PieChart(400, 400, array(255,255,255));

$chart->addSlice(15, array(255,0,0), true);
$chart->addSlice(5,  array(255,255,0), true);
$chart->addSlice(35, array(0,255,0));
$chart->addSlice(30, array(0,255,255));
$chart->addSlice(15, array(0,0,255));

$chart->render('pie.png');
?>

Verilen yüzdeler yalnızca örnek verilerdir. Derby'den sonuç kümesini nasıl oluşturacağınız ve her bir müşteri sayısını tüm müşterilerin bir yüzdesine nasıl dönüştüreceğiniz konusuna değinmedik. Ancak bu, standart bir veritabanı işlemidir ve biraz da elinizdeki işle ilgili bir konudur.





Sınıfın oluşturulması

Artık bir sınıf arabirimi örneğine sahip olduğunuza göre, sınıfı yaratarak boşlukları doldurabilirsiniz. Bu sınıfla ilgili özel olarak ileri düzey bir bilgi gerekmez. Dikkat edilmesi gereken tek ayrıntı, pastaya eklenen her dilimin saat yönünde eklendiğidir. explode özelliğinin true (doğru) olarak ayarlandığı her dilim için, dilimi pastadan ayırmak üzere kullanacağınız X ve Y ekseni yönlerini hesaplamanız gerekecektir (bkz. Liste 19).


Liste 19. 3 boyutlu pasta grafikler oluşturmak üzere kullanılacak PHP sınıfı
<?php
require_once 'Image/3D.php';

class PieChart {

    private $slices;
    private $width;
    private $height;
    private $bg;
    private $world;

    public function __construct($width, $height, $bg_list)
    {
        $this->width = $width;
        $this->height = $height;
        $this->bg = $bg_list;
    }

    public function addSlice ($percent, $color_list, $explode=false)
    {
        $this->slices[] = new PieChart_Slice($percent, 
                                             $color_list, $explode);
    }

    public function render ($filename)
    {
        $radius = round((min($this->width,$this->height) * 0.85) / 2);

        $world = new Image_3D();
        $world->setColor(new Image_3D_Color($this->bg[0], 
                                        $this->bg[1], $this->bg[2]));

        $light = $world->createLight(0, 1000, 1000);
        $light->setColor(new Image_3D_Color(255, 255, 255));

        $start = 0;
        foreach ($this->slices as $slice) {

            $end = $start + $slice->degrees;

            $options = array('start'   => $start,  
                             'end'     => $end,
                             'detail'  => 20,      
                             'outside' => $radius);
            $pie = $world->createObject('pie', $options);
            $color = new Image_3D_Color($slice->rgb[0], 
                                        $slice->rgb[1], 
                                        $slice->rgb[2]);
            if ($slice->explode) {
                $mid = $end - (($end - $start) / 2);
                $dx = cos(deg2rad($mid)) * ($radius * 0.15);
                $dy = sin(deg2rad($mid)) * ($radius * 0.15);
                $pie->transform($world->createMatrix('Move', 
                                                array($dx, $dy, 0)));
                $color->addLight($color, 0.4);
            }
            $pie->setColor($color);

            $start = $end;
        }

        $world->transform($world->createMatrix('Scale', 
                                                    array(1, 1, 10)));
        $world->transform($world->createMatrix('Rotation', 
                                                    array(-60, 0, 0)));

        $world->createRenderer('perspectively');
        $world->createDriver('zbuffer');
        $world->render($this->width, $this->height, $filename);
    }
}

class PieChart_Slice {

    public $percent;
    public $rgb;
    public $degrees;
    public $explode;

    public function __construct($percent, $color_list, $explode=false)
    {
        $this->percent = $percent;
        $this->rgb = $color_list;
        $this->explode = $explode;
        $this->degrees = 360 * ($percent / 100);
    }
}
?>

Sonuçta ortaya çıkan grafik aşağıda gösterilmiştir:


Şekil 19. Kırmızı ve sarı renkli dilimleri ayrılmış bir pasta grafik
Kırmızı ve sarı renkli dilimleri ayrılmış bir pasta grafik






Özet

Image_3D, dinamik olarak görüntüler oluşturmak üzere PHP'de kolayca kurulup kullanılabilecek bir PEAR paketidir. Sınıf arabirimi, PHP V5 sürümüyle ilgilenmiş olan herkes için anlaşılması kolay bir öğedir. Pakete dahil olan tüm nesne tiplerini, ışıkları, renkleri ve dönüştürmeleri incelediniz. Ayrıca basit komut satırı komut dosyalarıyla nasıl daha karmaşık uygulamalar oluşturabileceğinizi ve bunları Web üzerinde kullanılabilir yapmak üzere yararlanabileceğiniz bir stratejiyi de gördünüz. Son olarak, müdürünüzün çok beğeneceği pasta grafiklerin yaratılmasına yardımcı olacak basit bir sınıf tasarladınız.

Örneklerin tümünü hemen kullanacak olmayabilirsiniz. Ancak bu paketin hala alfa sürümünde olduğunu unutmayın. Herhangi bir işlevin eksik ya da hatalı olduğunu görürseniz PEAR istek listesine bir istek gönderebilirsiniz.






Karşıdan yükleme

Açıklama Ad Boyut Karşıdan yükleme yöntemi
PHP 3 boyutlu kod örneği os-php-3d.source.zip 779KB HTTP



Kaynaklar

Bilgi Edinme
  • PEAR:: Image_3D ürünü hakkındaki bilgileri okuyabilir ve bu ürünü kurabilirsiniz.

  • "Connecting PHP Applications to Apache Derby" (PHP Uygulamalarının Apache Derby'ye Bağlanması) başlıklı konuyu okuyarak pasta grafiği nasıl geliştireceğinizi öğrenebilirsiniz.

  • "Add interactivity to your SVG" (SVG'nize etkileşim eklenmesi) başlıklı konuyu okuyarak SVG görüntüleri ve komut dosyaları hakkında ek bilgi edinebilirsiniz.

  • "Getting started with objects with PHP V5" (PHP V5 ile nesnelere başlangıç) başlıklı konuyu okuyarak PHP V5 nesne/sınıf sözdizimi konusundaki bilgilerinizi tazeleyebilirsiniz.

  • Kartezyen koordinat sistemi hakkında ek bilgi edinmek için Cartesian coordinate system başlıklı sayfaya bakabilirsiniz.

  • PHP ve gd kitaplığını kullanarak dinamik bit eşlem görüntüleri oluşturma konusunda bilgi için Generate dynamic bitmap graphics with PHP and gd" (PHP ve gd ile dinamik bit eşlem grafikleri oluşturma) başlıklı konuyu okuyabilirsiniz.

  • PHP'de nesne odaklı bir grafik katmanı oluşturma hakkında bilgi almak için "Create graphics the smart way with PHP" (PHP ile akıllı grafikler yaratma) başlıklı konuyu okuyabilirsiniz.

  • developerWorks teknik etkinlikler ve Web yayınları sayesinde güncel bilgiler edinebilirsiniz.

  • developerWorks PHP proje kaynaklarını ziyaret ederek PHP becerilerini artırabilirsiniz.

  • developerWorks üzerine tüm PHP içeriğine göz atabilirsiniz.

  • Açık kaynak teknolojileri konusunda kendinizi geliştirmenize ve bunları IBM ürünleriyle kullanmanıza yardımcı olacak kapsamlı nasıl yapılır bilgileri, araçlar ve proje güncellemeleri için developerWorks Open source zone (Açık kaynak bölgesi) sayfasını ziyaret edebilirsiniz.


Ürün ve teknoloji edinme
  • Adobe's SVG Viewer eklentisini bilgisayarınıza yükleyebilirsiniz.

  • PHP komut dosyalarının yürütme süresini ölçmek için PEAR::Benchmark karşılaştırmalı değerlendirmesini kullanabilirsiniz.

  • Bilgisayarınıza yükleyebileceğiniz ya da DVD'sini edinebileceğiniz IBM deneme yazılımı ile yeni açık kaynak geliştirme projenizde değişiklik yapabilirsiniz.


Tartışma





Yazar hakkında

Mike Brittain, New York City'de Internet üzerinden tam kapsamlı pazarlama hizmetleri veren bir kuruluş olan ID Society'de teknoloji müdürüdür. 10 yılı aşkın bir süredir Web siteleri ve uygulamaları geliştirmekte olan Mike Brittain açık kaynak dilleri ve uygulamaları üzerine odaklanmıştır. Bilgisayarının başında olmadığında onu genellikle kayak ya da snowboard yaparken görebilirsiniz. Mike Brittain'a mike@mikebrittain.com adresinden ulaşabilirsiniz.

Görüşler

0
tongucyumruk
PHP gibi hiç yüz vermediğim bir dilde yapılabilen bu gibi şeyleri görmek oldukça ilginç oldu. Emeği geçen herkese teşekkürler.

Öhüm, şimdi de istek parçamız: Continuations and advanced flow control
0
FZ
Adamlar anket bile yapmışlar yahu! :)
0
butch
"Continuations and advanced flow control" çeviriliyor.
0
FZ
FM'nin sınırlarını zorlayan bu makalenin yayınlanmasında emeği geçen herkese teşekkürler. ;-)
0
anonim
Gerçekten sınırları zorlayan bir iş. Php den hiç ummazdım. Bu arada tonguç un söylediği şu contunation makalesi güzel olabilir....
Görüş belirtmek için giriş yapın...

İlgili Yazılar

Ajax Konusunda Uzmanlaşma, Bölüm 8

butch

IBM Türkiye ve Fazlamesai.net işbirliği ile dilimize kazandırılan yeni bir IBM developerWorks makalesi ile karşınızdayız. Diğer makalelere buradan ulaşabilirsiniz.

Makalenin özgün haline bu adresten ulaşabilirsiniz.

Python Web çerçeveleri, Bölüm 1

butch

IBM Türkiye ve Fazlamesai.net işbirliği ile dilimize kazandırılan yeni bir IBM developerWorks makalesi ile karşınızdayız. Diğer makalelere buradan ulaşabilirsiniz.

Makalenin özgün haline bu adresten ulaşabilirsiniz.

UNIX Dilinde Konuşma, Bölüm 6: Her şeyi otomatikleştirin!

butch

IBM Türkiye ve Fazlamesai.net işbirliği ile dilimize kazandırılan yeni bir IBM developerWorks makalesi ile karşınızdayız. Diğer makalelere buradan ulaşabilirsiniz.

Makalenin özgün haline bu adresten ulaşabilirsiniz.

Ajax Konusunda Uzmanlaşma, Bölüm 2

butch

IBM Türkiye ve Fazlamesai.net işbirliği ile dilimize kazandırılan yeni bir IBM developerWorks makalesi ile karşınızdayız. Diğer makalelere buradan ulaşabilirsiniz.

Makalenin özgün haline bu adresten ulaşabilirsiniz.

Ajax Konusunda Uzmanlaşma, Bölüm 4

butch

IBM Türkiye ve Fazlamesai.net işbirliği ile dilimize kazandırılan yeni bir IBM developerWorks makalesi ile karşınızdayız. Diğer makalelere buradan ulaşabilirsiniz.

Makalenin özgün haline bu adresten ulaşabilirsiniz.