Anda di halaman 1dari 17

Istilah-istilah penting :

Serializable artinya suatu objek dapat disimpan ke dalam stream of bytes sehingga objek
dapat ditransmit ke memory, database, atau file. Kegunaannya adalah untuk menyimpan state
dari objek tersebut sehingga dapat dibuat ulang ketika dibutuhkan.
Enumerasi adalah type berbeda yang mengandung sehimpunan konstanta.
Readonly artinya method/function pada kelas tersebut tidak dapat melakukan perubahan
pada variabel tersebut, kecuali melalui konstruktornya.
CLASS TEMPLATE
Class ini berisi informasi tentang template citra secara global beserta informasi
mengenai Minutia-minutia yang tersimpan di dalam Template tersebut. Kumpulan minutiaminutia tersimpan dalam array of minutia yang bernama Minutiae.
[Serializable]
public sealed class Template : ICloneable
{
public enum MinutiaType : byte
{
Ending = 0,
Bifurcation = 1,
Other = 2
}

Class template ini juga terdiri dari field bertype Struct yaitu Minutia. Memiliki tiga
field yaitu Position, Direction, dan Minutia Type. Untuk melakukan pengisian value Minutia
akan menggunakan constructor yang mengambil parameter input dari TemplateBuilder
Minutia.
[Serializable]
public struct Minutia
{
public readonly PointS Position;
public readonly byte Direction;
public readonly MinutiaType Type;

Class Template Builder sebenarnya sama saja dengan class Template, hanya saja
dia tidak serializable. Method ToBuilderMinutia() ini akan menyimpan property-property
(value) yang ada dalam objek Template tersebut ke dalam objek baru yang bertipe
TemplateBuilder.Minutia.

PointS adalah type data Point yang diSerializable, menyimpan data posisi x dan y dari
minutia.
Variabel Direction bertype data byte menyimpan semua kemungkinan arah minutiae,
karena byte bernilai 8 bit maka jumlah kemungkinana arah minutiae adalah 2^8 = 256.
Sedangkan MinutiaType, seperti dijelas

public Minutia(TemplateBuilder.Minutia builderMinutia)


{
Position = new PointS(builderMinutia.Position);
Direction = builderMinutia.Direction;

switch (builderMinutia.Type)
{
case TemplateBuilder.MinutiaType.Ending: Type = MinutiaType.Ending; break;
case TemplateBuilder.MinutiaType.Bifurcation: Type =
MinutiaType.Bifurcation; break;
case TemplateBuilder.MinutiaType.Other: Type = MinutiaType.Other; break;
default: throw new ApplicationException();
}
}

Dapat juga mengexport Minutia menjadi TemplateBuilder Minutia.


public TemplateBuilder.Minutia ToBuilderMinutia()
{
TemplateBuilder.Minutia builderMinutia = new TemplateBuilder.Minutia();
builderMinutia.Position = Position;
builderMinutia.Direction = Direction;
switch (Type)
{
case MinutiaType.Ending: builderMinutia.Type =
TemplateBuilder.MinutiaType.Ending; break;
case MinutiaType.Bifurcation: builderMinutia.Type =
TemplateBuilder.MinutiaType.Bifurcation; break;
case MinutiaType.Other: builderMinutia.Type =
TemplateBuilder.MinutiaType.Other; break;
default: throw new ApplicationException();
}
return builderMinutia;
}
public readonly int OriginalDpi;
public readonly int OriginalWidth;
public readonly int OriginalHeight;
public readonly int StandardDpiWidth;
public readonly int StandardDpiHeight;
public readonly Minutia[] Minutiae;

Fungsi Class Template pada intinya adalah sebagai tempat penyimpanan array of Minutia
yang bernama Minutiae. Sehingga konstruktornya, yang menerima input berupa
TemplateBuilder akan menjadi seperti ini :
public Template(TemplateBuilder builder)
{
OriginalDpi = builder.OriginalDpi;
OriginalWidth = builder.OriginalWidth;
OriginalHeight = builder.OriginalHeight;
StandardDpiWidth = builder.StandardDpiWidth;
StandardDpiHeight = builder.StandardDpiHeight;
Minutiae = new Minutia[builder.Minutiae.Count];
for (int i = 0; i < builder.Minutiae.Count; ++i)
Minutiae[i] = new Minutia(builder.Minutiae[i]);
}

CLASS FINGERPRINT
Kelas ini dapat menyimpan representasi fingerprint baik dalam bentuk Bitmap,
citra dalam byte, maupun template dalam bentuk SA Template, ISO template, dan XML

template. Namun dalam satu object kelas fingerprint tidak dapat menyimpan ketiga template
tersebut secara bersamaan, hanya satu saja. Ini disebabkan karena template-template tersebut
akan dibaca sebagai satu minutiae template. Selain itu juga menyimpan indeks Finger
(indeks finger ini tersimpan dalam kelas tersendiri yang mengenumerasi tipe-tipe
fingerprint).
Kelas ini clonable, artinya dapat membuat instansiasi objek lain dari kelas ini yang
memiliki nilai yang sama terhadap objek yang sudah ada.
CLASS PERSON
Kelas ini dapat menyimpan list fingerprint-fingerprint yang dimiliki oleh seorang
Person. Selain fingerprint juga dapat menyimpan integer ID. Sama seperti class fingerprint,
kelas Person juga clonable.
CLASS AFIS ENGINE
Kelas ini berisi method-method yang ada dalam proses biometrik sidik jari, yaitu
Ekstraksi, Identifikasi, dan Verifikasi Sidik Jari.

PROSES
MATCHING
MENGGUNAKAN
TEMPLATE DI SOURCEAFIS

MINUTIA

Berikut adalah baris-baris perintah untuk melakukan proses pemadanan :


byte[] kiri_01 = rb.setTemplate2Bytes("D:\\Research and Development\\ISO Template\\00",
"1.iso");
byte[] kiri_02 = rb.setTemplate2Bytes("D:\\Research and Development\\ISO Template\\10",
"1.iso");
byte[] kanan_01 = rb.setTemplate2Bytes("D:\\Research and Development\\ISO
Template\\01", "1.iso");
byte[] kanan_02 = rb.setTemplate2Bytes("D:\\Research and Development\\ISO
Template\\11", "1.iso");
Fingerprint fpProbe = new Fingerprint();
Fingerprint fpCandidate = new Fingerprint();
fpProbe.AsIsoTemplate = kiri_01;
fpCandidate.AsIsoTemplate = kiri_02;

Terlihat bahwa input yang dimasukkan adalah file iso template. File iso template tersebut akan dibaca
sebagai file stream of bytes, sehingga yang akan kita dapatkan adalah variabel dalam bentuk array of
bytes. Kita akan mengambil jari kiri sebanyak dua impression dan jari kanan sebanyak dua
impression.
Kemudian kita membuat object baru fpProbe dan fpCandidate bertipe Fingerprint. Begitu juga kita
mengeset value sebagai isoTemplate :
public byte[] AsIsoTemplate
{
get { return Decoded != null ?
IsoFormat.Export(SerializedFormat.Import(Decoded)) : null; }
set { Decoded = value != null ?
SerializedFormat.Export(IsoFormat.Import(value)) : null; }
}

Karena di sini kita akan mengisi value untuk objek internal Template Decoded (yang akan kita
gunakan untuk proses pemadanan), maka di sini akan masuk ke perintah set Decoded value dengan

cara melakukan Import value dari isoFormat menjadi objek Template tersebut.
Person probe_02 = new Person(fpProbe);
Person candidate_02 = new Person(fpCandidate);
float hasilku = Afis_02.Verify(probe_02, candidate_02);

Untuk melakukan proses Verify harus dimasukkan ke dalam object Person terlebih dahulu.
Untuk penjelasan-penjelasan di bawah ini sudah masuk ke fungsi Verify :
Di kelas AfisEngine telah dibuat satu instansiasi object Matcher yang bertype ParallelMatcher :
ParallelMatcher Matcher = new ParallelMatcher();

Object ini akan digunakan kemudian.


probe.CheckForNulls();
candidate.CheckForNulls();
BestMatchSkipper collector = new BestMatchSkipper(1, MinMatches - 1);

Sebelum melakukan proses matching, kedua parameter input fungsi, Person probe dan Person
candidate, akan dicek terlebih dahulu apakah kedunya memiliki fingerprint atau tidak. Jika salah satu
atau semua dari keduanya tidak memiliki fingerprint, maka Aplikasi akan selesai secara paksa (force
exit) sambil mengeluarkan pesan error Person contains null Fingerprint references.
Instance collector yang berjenis kelas BestMatchSkipper bertindak sebagai pengumpul hasil score
pemadanan. Pada kasus Verify ini, nilai MinMatches adalah 1. MinMatches adalah jumlah fingerprint
minimal yang harus match agar pemadanan orang itu dikatakan match.
public BestMatchSkipper(int persons, int skip)
{
Collected = new float[skip + 1][];
for (int i = 0; i < Collected.Length; ++i)
{
Collected[i] = new float[persons];
for (int j = 0; j < Collected[i].Length; ++j)
Collected[i][j] = -1;
}
}

BestMatchSkipper akan membuat sebuah array 2-Dimensi bernama Collected berukuran skip x
persons. Sebagai instansiasi awal semua elemen array bernilai -1.
Parallel.ForEach(probe.Fingerprints, probeFp =>
{
//Code Here...
}

Syntax Parallel.ForEach(probe.Fingerprints, probeFP di atas sama dengan syntax :


foreach (Fingerprint probeFp in probe.Fingerprints){
//My Stuf}

Artinya kita melakukan iterasi elemen-elemen yang ada pada List


probe.Fingerprints.

of

Fingerprints

Berikut adalah perbedaan antara foreach loop dan Parallel.ForEach :


No.
1
2
3
4

Foreach Loop
Iterasi dilakukan secara sekuensial
satu demi satu
Foreach loop dijalankan dari Thread
tunggal
Foreach loop terdefinisikan di semua
framework .NET
Eksekusinya lebih lambat

Parallel.ForEach
Eksekusi dilakukan secara paralel
Parallel.ForEach
menggunakan
Thread
Parallel.ForEach
terdefinisi
framework .NET 4.0 ke atas
Eksekusinya lebih cepat

banyak
mulai

var candidateTemplates = (from candidateFp in candidate.Fingerprints


where IsCompatibleFinger(probeFp.Finger, candidateFp.Finger)
select candidateFp.Decoded).ToList();

SourceAFIS juga menggunakan syntax LINQ. LINQ adalah sekumpulan fitur yang diperkenalkan
mulai Visual Studio 2008 yang meningkatkan kapabilitas query yang kuat ke dalam syntax C# dan
Visual Basic. LINQ dapat mempercepat pengerjaan program, karena codenya dapat menjadi lebih
singkat dibandingkan penulisan kode program secara tradisional. LINQ juga mendukung fungsi-fungsi
SQL seperti Where, Select, Group By, Join, Max, dan Average. Kita lihat outputnya, variabel
candidateTemplate yang didapatkan hanya satu saja.

Pada potongan kode program di atas, kita mengambil Template Fingerprint dari Fingerprintfingerprint yang dimiliki kandidat jika Finger Candidate tersebut kompatible dengan Finger Probe.
Apa yang dimaksud dengan kompatibel?
bool IsCompatibleFinger(Finger first, Finger second)
{
return first == second || first == Finger.Any || second == Finger.Any;
}

Seperti kita ketahui, Finger adalah enumerasi jenis sidik jari. Maka fungsi di atas akan mengecek

apakah kedua finger memiliki type enumerasi yang sama (misalnya sama-sama berjenis telunjuk,
jempol, dll.), atau finger pertama berjenis sembarang atau finger pertama berjenis sembarang. Jika
memenuhi salah satu dari ketiganya maka return true. Mengapa perlu dicek kompatibilitasnya? Karena
kita tidak dapat melakukan matching pada dua Finger yang enumerasinya berbeda (misalnya jari
telunjuk dengan kelingking). Lihat kembali kondisi pertama.
ParallelMatcher.PreparedProbe probeIndex = Matcher.Prepare(probeFp.Decoded);

Potongan code tersebut berisi tahapan-tahapan rinci pemanggilan fungsi-fungsi yang ada di
SourceAFIS untuk melakukan pemadanan. Terlihat bahwa parameter input yang dimasukkan adalah
probeFp.Decoded, yang merupakan Template Fingerprint dari Person Probe, dalam hal ini orang yang
akan di-padan-kan. Fungsi ini dipanggil dari object Matcher yang telah didefinisikan sebelumnya
(pada saat deklarasi objek AfisEngine).
Pertama kita akan masuk ke fungsi Prepare :
public PreparedProbe Prepare(Template probe)
{
PreparedProbe prepared = new PreparedProbe();
MinutiaMatcher matcher = DequeueMatcher();

Object prepared merupakan instansiasi dari kelas PreparedProbe(). Sampai sini belum ada operasi
apapun terhadap object tersebut sehingga kita langsung mengkaji ke baris berikutnya, yaitu
pemanggilan fungsi DequeueMatcher. Terlihat bahwa inisiasi object prepared pada saat ini hanya
menghasilkan ProbeIndex yang kosong.

Kita masuk ke class ParallelMatcher.cs :


public MinutiaMatcher MinutiaMatcher = new MinutiaMatcher();
Queue<MinutiaMatcher> Matchers = new Queue<MinutiaMatcher>();
MinutiaMatcher DequeueMatcher()
{
MinutiaMatcher matcher = null;
lock (Matchers)
if (Matchers.Count > 0)
matcher = Matchers.Dequeue();
if (matcher == null)
matcher = ParameterSet.ClonePrototype(MinutiaMatcher);
return matcher;

Class ParallerMatcher ini memiliki atribut Queue of MinutiaeMatcher yang bernama Matchers.
Sampai saat ini belum terlihat kegunaannya. Queue merupakan tipe data di C# yang
merepresentasikan koleksi object first-in, first-out. Sedangkan dequeue akan menghapus dan
mengembalikan objek pada bagian depan Queue.

Seperti terlihat bahwa jumlah Matchers-Countnya adalah 0, sehingga masuk ke baris berikutnya
apakah matcher adalah null. Karena masih null juga, maka akan masuk ke baris ClonePrototype.
Kegunaan dari method DequeueMatcher ini adalah untuk mengembalikan MinutiaMatcher apa yang
akan digunakan, walapun sampai saat ini belum diketahui seperti apa penggunaan MinutiaeMatcher
tersebut.
public static T ClonePrototype<T>(T prototype) where T : class
{
T clone = prototype.GetType().GetConstructor(Type.EmptyTypes).Invoke(null) as T;
ParameterSet parameters = new ParameterSet(new ObjectTree(prototype));
parameters.Rebind(new ObjectTree(clone));
parameters.SaveValues();
DetailLogger.CopyHooks(prototype, clone);
return clone;
}

Berikut adalah hasil proses cloning yang dilakukan terhadap variabel MinutiaMatcher.

try
{

matcher.BuildIndex(probe, prepared.ProbeIndex);
}
finally
{
EnqueueMatcher(matcher);
}
return prepared;

Berikutnya langsung masuk saja ke baris BuildIndex dengan parameter masukan probe yang berjenis
Template (probe di sini adalah Template Minutia dari person yang akan dipadankan). Sementara
prepared.probeIndex, seperti yang kita lihat tadi, isinya masih null.
Berikut adalah isi dari method BuildIndex. Method ini berada dalam class ParallelMatcher.cs :
public void BuildIndex(Template probe, ProbeIndex index)
{
index.Template = probe;
index.Edges = ParameterSet.ClonePrototype(EdgeTablePrototype);
index.Edges.Reset(probe);
index.EdgeHash = new EdgeHash(probe, EdgeLookup);
}

Pertama, Template probe akan di-assign sebagai Template dari index :

Selanjutnya, field Edges dari objek bertipe class ParallelMatcher tersebut akan diisi (diassign) dengan
Prototype Edge Table. EdgeTablePrototype itu sendiri berjenis class EdgeTable.

Berikut adalah class EdgeTable dan field-field yang dimilikinya :


public sealed class EdgeTable
{
[Nested]
public EdgeConstructor EdgeConstructor = new EdgeConstructor();
[Parameter(Lower = 30, Upper = 1500)]
public int MaxDistance = 490;
[Parameter(Lower = 2, Upper = 100)]
public int MaxNeighbors = 9;
public DetailLogger.Hook Logger = DetailLogger.Null;
public NeighborEdge[][] Table;

Terlihat di atas bahwa index.Edges telah dideklarasikan, walaupun field Table masih belum diisi
(null).
Di baris berikutnya terlihat SourceAFIS akan mengerjakan method Reset, dengan parameter input
Template, dalam hal ini adalah probe, yang merupakan parameter input dari method BuildIndex.
Berikut adalah fungsi Reset tersebut :
public void Reset(Template template)
{
lock (template)
Table = template.MatcherCache as NeighborEdge[][];
if (Table == null)
{
BuildTable(template);
lock (template)
template.MatcherCache = Table;
}
}

Logger.Log(this);

Terlihat ada proses pemanggilan operator as terhadap field MatcherCache yang dimiliki oleh objek
template. Pemanggilan operator as ini berarti bahwa kita melakukan konversi type tertentu antara
reference type yang kompatible atau nullable types. Di sini berarti field MatcherCache akan bertindak
sebagai array of NeighborEdge. Berikut adalah class NeighborEdge :

public struct NeighborEdge


{
public EdgeShape Edge;
public int Neighbor;
}

Dalam class NeighborEdge tersebut memiliki satu field member yang bertipe EdgeShape.
public struct EdgeShape
{
public short Length;
public byte ReferenceAngle;
public byte NeighborAngle;
}

Salah satu fungsi penting yang akan dijalankan adalah BuildTable. Method ini berada di class
EdgeTable :
void BuildTable(Template template)
{
Table = new NeighborEdge[template.Minutiae.Length][];
var edges = new List<NeighborEdge>();
var allSqDistances = new int[template.Minutiae.Length];

Field Table akan diisi oleh array 2 dimensi berukuran panjang sebanyak jumlah Minutia. Dalam kasus
ini 65.

Variable edges akan dideklarasikan sebagai list(kosong) dari class NeighborEdge. NeighborEdge
sendiri memiliki field bertipe data class EdgeShape dan integer.
public struct NeighborEdge
{
public EdgeShape Edge;
public int Neighbor;
}

Sedangkan EdgeShape sendiri memiliki satu field bertipe short dan dua bertipe byte.
public struct EdgeShape
{
public short Length;
public byte ReferenceAngle;
public byte NeighborAngle;
}

Baris berikutnya akan membuat objek edges, yang merupakan List dari tipe data NeighborEdge.
Kemudian membuat objek allSqDistances, yang merupakan array bertipe integer berukuran sebanyak
jumlah Minutia dari template.
for (int reference = 0; reference < Table.Length; ++reference)

Point referencePosition = template.Minutiae[reference].Position;


int sqMaxDistance = Calc.Sq(MaxDistance);

Kemudian masuk ke perhitungan untuk tiap-tiap Minutia. Maka dari itu akan dilakukan perulangan
sebanyak minutia yang ada pada template. Pertama akan diambil titik acuan yaitu objek
referencePosition yang bertipe data Point. Nilai sqMaxDistance sendiri adalah kuadrat dari nilai
MaxDistance. Di sini MaxDistance ditetapkan bernilai 490, sehinga nilai dari sqMaxDistance adalah
490 * 490 = 240100.
if (template.Minutiae.Length - 1 > MaxNeighbors)
{
for (int neighbor = 0; neighbor < template.Minutiae.Length; ++neighbor)
allSqDistances[neighbor] = Calc.DistanceSq(referencePosition,
template.Minutiae[neighbor].Position);
Array.Sort(allSqDistances);
sqMaxDistance = allSqDistances[MaxNeighbors];
}

Selanjutnya masuk ke perhitungan jarak dari reference minutia ke minutia-minutia lainnya yang ada
pada template. Syaratnya jika jumlah minutia yang ada dikurangi satu lebih banyak dari nilai
MaxNeighbors. Di sini SourceAFIS menetapkan nilainya adalah 9. Hasilnya disimpan di dalam array
allSqDistance yang berukuran sebesar jumlah minutiae. Persamaan untuk menghitung Square
Distance sendiri adalah :

PointA.width-PointB.width)

PointA.height-PointB.height)

SqDistance =
Dimana

PointA
di
sini
adalah
referencePosition,
dan
PointB
adalah
template.Minutiae[neighbor].Position . Persamaan tersebut didapatkan dari langkah-langkah di
bawah ini :
public static int DistanceSq(Point left, Point right)
{
return DistanceSq(Diference(left, right));
}
public static Point Diference(Point left, Point right)
{
return left - new Size(right);
}
public static Point operator -(Point left, Size right)
{
return new Point(left.X - right.Width, left.Y - right.Height);
}
public static int DistanceSq(Point point)
{
return Sq(point.X) + Sq(point.Y);
}

Kemudian array allSqDistances tersebut diurutkan menurut increasing order (dari terendah ke
tertinggi). Kemudian didapatkan nilai SqMaxDistance yakni sebesar allSqDistances[9]. 9 di sini
adalah nilai maxNeighbour.
Setelah array allSqDistances dibuat dan terisi dalam increasing order, berikutnya adalah adalah
mengisi ArrayList edges, yang berisi NeigborEdge dari titik minutia reference. Dilakukan perulangan
untuk setiap minutia, selain minutia reference, untuk mengisi ArrayList edges tersebut. Syaratnya
adalah jarak kuadrat (distanceSq) dari minutiae reference ke minutiae neighbornya (tetangganya)
harus kurang dari sqMaxDistance.
for (int neighbor = 0; neighbor < template.Minutiae.Length; ++neighbor)
{
if (neighbor != reference && Calc.DistanceSq(referencePosition,
template.Minutiae[neighbor].Position) <= sqMaxDistance)
{
NeighborEdge record = new NeighborEdge();
record.Edge = EdgeConstructor.Construct(template, reference, neighbor);
record.Neighbor = neighbor;
edges.Add(record);
}
}

Pertama-tama akan menginisialisasi object baru record yang bertipe NeighborEdge. NeighborEdge
berisi EdgeShape Edge dan integer Neighbor. Untuk menginisiasi nilai kedua property tersebut,
digunakan method Construct yang akan mempassing nilai template, reference, dan neighbor.
public EdgeShape Construct(Template template, int reference, int neighbor)
{
PolarPoint polar =
Angle.ToPolar(Calc.Diference(template.Minutiae[neighbor].Position,
template.Minutiae[reference].Position));
EdgeShape edge;
edge.Length = (short)polar.Distance;
edge.ReferenceAngle = Angle.Diference(template.Minutiae[reference].Direction,
polar.Angle);
edge.NeighborAngle = Angle.Diference(template.Minutiae[neighbor].Direction,
Angle.Opposite(polar.Angle));
return edge;
}

Pertama akan dikalkulasi PolarPoint dari kedua point tersebut PolarPoint. Tipe data PolarPoint terdiri
dari integer dan byte.
struct PolarPointB
{
public short Distance;
public byte Angle;
}

Untuk konversi ke PolarPoint, pertama akan dibuat PolarCache terlebih dahulu, yaitu array 2-dimensi
dari PolarPointB.
public static PolarPoint ToPolar(Point point)
{

if (PolarCache == null)
PolarCache = CreatePolarCache();
int quadrant = 0;
int x = point.X;
int y = point.Y;
if (y < 0)
{
x = -x;
y = -y;
quadrant = 128;
}
if (x < 0)
{
int tmp = -x;
x = y;
y = tmp;
quadrant += 64;
}
int shift = Calc.HighestBit((uint)(x | y) >> PolarCacheBits);

PolarPointB polarB = PolarCache[y >> shift, x >> shift];


return new PolarPoint(polarB.Distance << shift, (byte)(polarB.Angle + quadrant));

Konstanta unsigned integer PolarCacheRadius bernilai 256, yang didapatkan dari shift left angka 1
sejauh 8 bit, artinya 28.
const uint PolarCacheRadius = 1u << PolarCacheBits;
static PolarPointB[,] CreatePolarCache()
{
PolarPointB[,] cache = new PolarPointB[PolarCacheRadius, PolarCacheRadius];
for (int y = 0; y < PolarCacheRadius; ++y)
for (int x = 0; x < PolarCacheRadius; ++x)
{
cache[y, x].Distance = Convert.ToInt16(Math.Round(Math.Sqrt(Calc.Sq(x) +
Calc.Sq(y))));
if (y > 0 || x > 0)
cache[y, x].Angle = Angle.AtanB(new Point(x, y));
else
cache[y, x].Angle = 0;
}
return cache;
}

PolarPointB 2-dimensi adalah aray berukuran 256 x 256. 256 adalah jumlah banyaknya kombinasi
sudut yang dapat disimpan dalam ISO template (0 360 derajat, dikuantiasi menjadi 0 256).
Kemudian dilakukan perulangan (nested loop) untuk nilai x=0 sampai dengan 255, dan y=0 sampai
dengan 255. Field distance dari array cache akan diisi dengan
x2 + y 2 . Hasil dari perhitungan ini
adalah dalam tipe data double, di cast menjadi nilai integer 16 bit.

Berikut adalah ilustrasi dari field Distance pada array cache. Ke arah horizontal adalah nilai x,
sedangkan vertical nilai y. Hanya ditampilkan untuk nilai x = 0 hingga 5 dan y = 0 hingga 5.

0
1
2
3
4
5

1
1.414
214
2.236
068
3.162
278
4.123
106
5.099
02

2
2.236
068
2.828
427
3.605
551
4.472
136
5.385
165

3
3.162
278
3.605
551
4.242
641
5
5.830
952

4
4.123
106
4.472
136
5
5.656
854
6.403
124

5
5.099
02
5.385
165
5.830
952
6.403
124
7.071
068

Field Angle dari array cache akan diisi dengan nilai arcus tangen (y/x), kecuali untuk koordinatkoordinat dengan nilai x=0 dan y=0.
public static byte AtanB(Point point)
{
return ToByte(Atan(point));
}

Pertama kita akan membuka fungsi Atan terlebih dahulu, yang mempassing variable point. Seperti
terlihat pada source code sebelumnya. Sebelumnya kita mendeklarasikan object Point baru dengan
nilai Point.X = koordinat x dan Point.Y = koordinat y.
public static float Atan(Point point)
{
return Atan(point.X, point.Y);
}

Method Atan2 pada C# akan mengembalikan tangent dari hasil pembagian dua angka inputan.
Hasilnya bertipe data Double yang merupakan nilai sudut yang diukur dalam radian, dimana
, dan tan ( ) = y / x , namun dalam kasus ini (berdasarkan tulisan kode sumber)
tan ( ) =x / y .
public static float Atan(double x, double y)
{
double result = Math.Atan2(y, x);
if (result < 0)
result += 2 * Math.PI;
return (float)result;
}

Variabel result tersebut di atas kemungkinan menghasilkan nilai radian di kuadran III dan IV (bernilai
negative). Jika hal tersebut terjadi, maka nilai result akan ditambahkan sebanyak 2 sehinga
nilainya selalu positif. (berada di kuadran I atau II). Atau dengan kata lain, dicerminkan terhadap
sumbu-x.
public static int Quantize(float angle, int resolution)

int result = (int)(ToFraction(angle) * resolution);


if (result < 0)
return 0;
else if (result >= resolution)
return resolution - 1;
else
return result;

Kemudian mengkuantisasi nilai radian tersebut ke 0 256 dengan menggunakan persamaan :

norm=

256
2

Persamaan lengkap untuk matrix cache Angle :

tan1
cache ( y , x ) . Angle=

( xy ) 256

Hasil dari syntax-syntax di atas adalah array cache sebagai berikut :

Untuk fungsi CreateHighestBitCache akan membuat array satu dimensi bernama result bertipe data
byte berukuran 1 x 256. Anggap nilai i adalah 1 hingga 256, untuk masing-masing i, nilai dari result
[i] adalah nilai x (integer positif) terbesar yang memenuhi 2( x1 )<i , atau dengan notasi lain
log 2 (x1)<i .
static byte[] CreateHighestBitCache()
{
byte[] result = new byte[256];
for (uint i = 0; i < 256; ++i)
{
int highest = 0;
for (uint j = i; j > 0; j >>= 1)
++highest;
result[i] = (byte)highest;
}
return result;
}

Operasi tersebut dipanggil untuk menginisiasi array static HighestBitCache, yang akan digunakan
pada beberapa operasi berikutnya.
static byte[] HighestBitCache = CreateHighestBitCache();

Berikut ini adalah output yang dihasilkan dari syntax di atas :

Syntax berikutnya adalah tentang posisi x dan y serta perpindahan kuadran menurut posisi. Terlihat di
bawah ini bahwa jika posisi y adalah negative maka nilai x dan y akan dikalikan -1, dan nilai kuadran
menjadi 128. Kemudian dicek lagi apakah nilai x negative. Jika negative maka nilai y menjadi x dan
nilai x menjadi y. Nilai kuadran ditambah 64. Sampai langkah ini belum terlihat dengan jelas
kegunaan variable-variabel tersebut.
int quadrant = 0;
int x = point.X;
int y = point.Y;
if (y < 0)
{
x = -x;
y = -y;
quadrant = 128;
}
if (x < 0)
{
int tmp = -x;
x = y;
y = tmp;
quadrant += 64;
}

Berikutnya adalah menghitung pergeseran (shift) berdasarkan syntax di bawah ini :


int shift = Calc.HighestBit((uint)(x | y) >> PolarCacheBits);

Dapat dilihat terdapat operasi operator logika OR dan bitwise shift right sebanyak 8 bit (nilai variable
PolarCacheBits). Berikut akan ditampilkan ilustrasi perhitungan kedua operasi tersebut, dimulai dari
operator logika OR :

Misalkan ada dua buah variable integer x=35 dan y=9, maka x | y diperoleh dengan mengkonversi x
dan y terlebih dahulu ke basis 2 :
x = 35 -> 0100011, y = 9 -> 0001001
Kemudian akan dihitung bitwise OR-nya : (0100011) | (0001001) = 0101011 -> konversi ke decimal
bernilai 43.
Operator >> akan menggeser bit dari ekspression1 (inputan kiri) ke kanan sejauh jumlah bit yang
dispesifikkan pada expression2 (inputan kanan). Tanda bit dari expression1 digunakan untuk mengisi
digit dari kiri, Digit yang digeser ke kanan akan dibuang. Untuk memastikan bahwa setiap pergeseran
menyisakan sekurangnya satu digit dari bit asalnya, operator shift menggunakan rumus berikut ini
untuk mengkalkulasi nilai pergesera actual : me-masking expression2 (menggunakan operator bitwise
AND) dengan nilai satu kurang dari jumlah bit pada expression1.

The >> operator shifts the bits of expression1 right by the number of bits specified
in expression2. The sign bit of expression1 is used to fill the digits from the left. Digits
shifted of to the right are discarded.
Misalka
You can use the as operator to perform certain types of conversions between compatible
reference types or nullable types. The following code shows an example.

Because LINQ queries are integrated into the C# language, it is possible for
you to write code much faster than if you were writing oldstyle queries. In
some cases, developers have seen their development time cut in half.

Represents a first-in, first-out collection of objects.


Removes and returns the object at the beginning of the Queue.
Language-Integrated Query (LINQ) is a set of features introduced in Visual Studio 2008
that extends powerful query capabilities to the language syntax of C# and Visual Basic.
LINQ introduces standard, easily-learned patterns for querying and updating data, and the
technology can be extended to support potentially any kind of data store.
Beginning in Visual C# 3.0, variables that are declared at method scope can have an
implicit type var. An implicitly typed local variable is strongly typed just as if you had
declared the type yourself, but the compiler determines the type. The following two
declarations of i are functionally equivalent:

Type describes data types. It stores type information in a


variable, property or field. The Type class represents the
program's metadata, which is a description of its structure but
not the instructions that are executed.

Anda mungkin juga menyukai