Senin, 04 Agustus 2014

Neighbor Prediction And Scoring

Post ini ada kaitannya dgn post saya yg ini. Jadi tool utk predict dan scoring neighbor yg sebelumnya dibikin pke VBA, skrg dibikin pke mapbasic. Tentu keuntungannya yaitu hasil dr prediksi dan scoring nya bisa lngsung keliatan di mapinfo.

Konsepnya sederhana aja sih, yg dikatakan best neighbor list menurut tool ini yaitu yg attempt ncell nya besar, jarak paling deket, posisi site target yg ada di beam radius si source, ama azimuth si target nya yg ngarah ke source.

Modal utk ngbikin prediction dan scoring ya cuma 3 table yaitu data cell, Nbr table, dan NCell table. Kita coba bahas dulu utk 3G to 3G prediction and scoring aja dulu (toh 3G ke 2G dan 2G ke 2G sama aja koq konsepnya, cuma table2 nya aja diganti).

Detail mapbasic codenya beginih.. (moga bermanfaat dan klo ada yg punya ide lain utk metode prediksinya boleh donk di sharing ilmunya hehe)

Predict Neighbors :
if isUseSHOforPredict=1 then
select * from SHO_NCell where Source=sourceId into qCreateSHO noselect
Commit Table qCreateSHO As myAppDir + "Table\tmpSHO_NCell.TAB" TYPE NATIVE Charset "WindowsLatin1"
Open Table myAppDir + "Table\tmpSHO_NCell.TAB" Interactive
close table qCreateSHO
select Max(SHO_Att) "MaxSHO" from tmpSHO_NCell where Source=sourceId into qSHO noselect
fMaxSHO=qSHO.MaxSHO
close table qSHO
end if

select * from Data_3G_Cell where Carrier=sCarrierTarget3G and Distance( startX, startY, Longitude, Latitude, "km" ) <= fMaxDistance into qRel


do while not EOT(qRel)

targetId=qRel.RNC_CellID
tx=centroidx(qRel.Obj)
ty=centroidy(qRel.Obj)
endX=qRel.Longitude
endY=qRel.Latitude
aztarget=qRel.Azimuth

if sourceId<>targetId then
'read SHO att value
if isUseSHOforPredict=1 then
select * from tmpSHO_NCell where Source=sourceId and Target=targetId into qSHO noselect
currentSHO=qSHO.SHO_Att
if fMaxSHO > 0 then
fRateSHO=(currentSHO/fMaxSHO)*100
else
fRateSHO=0
end if
close table qSHO
else
currentSHO=0
fRateSHO=0
end if

'calculate rate distance
fRateDistance=((fMaxDistance - Distance(startX,startY,endX,endY,"km")) / fMaxDistance) * 100
'calculate rate azimuth
call analyzeNeighbour(startX,startY,endX,endY,azsource,aztarget,fRingWidth)
'calculate average rate
call calculate_AverageRate

'insert to tblPredict
insert into tblPredict (Source,Target,SHO_Att,Distance_Km,Rate_SHO,Rate_Distance,Rate_Ring,Rate_TargetToBothDir,Rate_TargetToSource,Rate_Average) 
values (sourceId,targetId,currentSHO,Distance(startX,startY,endX,endY,"km"),fRateSHO,fRateDistance,fRateRing,fRateBothDir,fRateAntDir,fRateAverage)
end if
fetch next from qRel
loop

Analyze Neighbors :
Sub analyzeNeighbour(ByVal StartLong as float,ByVal StartLat as float,ByVal EndLong as float,ByVal EndLat as float,ByVal fDirSource as float,ByVal fDirTarget as float,ByVal fRingWidth as float)
if fDirSource >= 0 and fDirSource < 90 then
mapDirSource = 90 - fDirSource
elseif fDirSource >= 90 and fDirSource < 180 then
mapDirSource = 360 - (fDirSource - 90)
elseif fDirSource >= 180 and fDirSource < 270 then
mapDirSource = 180 + (270 - fDirSource)
elseif fDirSource >= 270 and fDirSource <= 360 then
mapDirSource = 90 + (360 - fDirSource)
end if

if fDirTarget >= 0 and fDirTarget < 90 then
mapDirTarget = 90 - fDirTarget
elseif fDirTarget >= 90 and fDirTarget < 180 then
mapDirTarget = 360 - (fDirTarget - 90)
elseif fDirTarget >= 180 and fDirTarget < 270 then
mapDirTarget = 180 + (270 - fDirTarget)
elseif fDirTarget >= 270 and fDirTarget <= 360 then
mapDirTarget = 90 + (360 - fDirTarget)
end if

'get direction between 2 longlat
myDirection = getDirection(StartLong,StartLat,EndLong,EndLat)

'rate for azimuth to ring
fRateRing = getRate_AzimuthToRingWidth(mapDirSource,fRingWidth,myDirection)

'calculate rate by source vs target azimuth --> makin berlawanan smakin bagus
fRateAntDir = getRate_AntDirection(mapDirSource,mapDirTarget)

'calculate rate by target azimuth vs both direction --> makin berlawanan smakin bagus
fRateBothDir = getRate_BothDirection(myDirection,mapDirTarget)
End Sub

Related Functions :
Function getDirection(ByVal StartLong as float,ByVal StartLat as float,ByVal EndLong as float,ByVal EndLat as float) as float
dLon = EndLong - StartLong
Ytmp = Cos(deg2rad(StartLat)) * Sin(deg2rad(EndLat)) - Sin(deg2rad(StartLat)) * Cos(deg2rad(EndLat)) * Cos(deg2rad(dLon))
Xtmp = Sin(deg2rad(dLon)) * Cos(deg2rad(EndLat))
Bearing = aTan2(Ytmp, Xtmp)
AZM = Round(rad2deg(Bearing), 0.1)
If AZM < 0 Then
            getDirection = 360 - Abs(AZM)
    Else
            getDirection = AZM
    End If
End Function

Function getRate_AzimuthToRingWidth(ByVal mapDirSource as float,ByVal fRingWidth as float,ByVal myDirection as float) as float

in_range = 0
Rw_start = mapDirSource - (fRingWidth / 2)
Rw_stop = mapDirSource + (fRingWidth / 2)

If (myDirection <= Rw_stop) And (myDirection >= Rw_start) Then
in_range = 1
If myDirection = mapDirSource Then
positionRate = 100
Else
If myDirection > mapDirSource Then
gap_angle = myDirection - mapDirSource
Else
gap_angle = mapDirSource - myDirection
End If
End If
ElseIf ((myDirection - 360) <= Rw_stop) And ((myDirection - 360) >= Rw_start) Then
in_range = 1
If (myDirection - 360) = mapDirSource Then
positionRate = 100
Else
If (myDirection - 360) > mapDirSource Then
gap_angle = (myDirection - 360) - mapDirSource
Else
gap_angle = mapDirSource - (myDirection - 360)
End If
End If
ElseIf ((myDirection + 360) <= Rw_stop) And ((myDirection + 360) >= Rw_start) Then
in_range = 1
If (myDirection + 360) = mapDirSource Then
positionRate = 100
Else
If (myDirection + 360) > mapDirSource Then
gap_angle = (myDirection + 360) - mapDirSource
Else
gap_angle = mapDirSource + (myDirection + 360)
End If
End If
End If

If in_range = True Then
positionRate = (((fRingWidth / 2) - gap_angle) / (fRingWidth / 2)) * 100
Else
positionRate = 0
End If
getRate_AzimuthToRingWidth = positionRate
End Function

Function getRate_BothDirection(ByVal bothDirection as float, ByVal mapDirTarget as float) as float

azsource = deg2rad(bothDirection)
aztarget = deg2rad(mapDirTarget)
cross_2_pi = 0

If (bothDirection >= 0) And (bothDirection < 90) Then

If (mapDirTarget >= 270) And (mapDirTarget < 360) Then
cross_2_pi = 1
on_rad_4 = "target"
End If
ElseIf (mapDirTarget >= 0) And (mapDirTarget < 90) Then
If (bothDirection >= 270) And (bothDirection < 360) Then
cross_2_pi = 1
on_rad_4 = "source"
End If
End If

If cross_2_pi = 1 Then

If on_rad_4 = "source" Then
azsource = azsource - (2 * pi)
ElseIf on_rad_4 = "target" Then
aztarget = aztarget - (2 * pi)
End If
End If

If aztarget > azsource Then
gap_azimuth = aztarget - azsource
ElseIf aztarget < azsource Then
gap_azimuth = azsource - aztarget
ElseIf aztarget = azsource Then
gap_azimuth = 0
End If

If gap_azimuth > pi Then

getRate_BothDirection = ((pi - (gap_azimuth - pi)) / pi) * 100
Else
getRate_BothDirection = (gap_azimuth / pi) * 100
End If
End Function

Function getRate_AntDirection(ByVal mapDirSource as float, ByVal mapDirTarget as float) as float

azsource = deg2rad(mapDirSource)
aztarget = deg2rad(mapDirTarget)
cross_2_pi = 0

If (mapDirSource >= 0) And (mapDirSource < 90) Then

If (mapDirTarget >= 270) And (mapDirTarget < 360) Then
cross_2_pi = 1
on_rad_4 = "target"
End If
ElseIf (mapDirTarget >= 0) And (mapDirTarget < 90) Then
If (mapDirSource >= 270) And (mapDirSource < 360) Then
cross_2_pi = 1
on_rad_4 = "source"
End If
End If

If cross_2_pi = 1 Then

If on_rad_4 = "source" Then
azsource = azsource - (2 * pi)
ElseIf on_rad_4 = "target" Then
aztarget = aztarget - (2 * pi)
End If
End If

If aztarget > azsource Then
gap_azimuth = aztarget - azsource
ElseIf aztarget < azsource Then
gap_azimuth = azsource - aztarget
ElseIf aztarget = azsource Then
gap_azimuth = 0
End If

If gap_azimuth > pi Then

getRate_AntDirection = ((pi - (gap_azimuth - pi)) / pi) * 100
Else
getRate_AntDirection = (gap_azimuth / pi) * 100
End If
End Function

Function deg2rad(ByVal deg As float) as float

    deg2rad = deg * pi / 180
End Function

Function rad2deg(ByVal rad As float) as float

    rad2deg = rad * 180 / pi
End Function

Function aTan2(ByVal Ytmp As float, ByVal Xtmp As float) as float

    If Xtmp > 0 Then
        aTan2 = Atn(Ytmp / Xtmp)
    ElseIf Xtmp < 0 And Ytmp >= 0 Then
        aTan2 = Atn(Ytmp / Xtmp) + pi
    ElseIf Xtmp = 0 And Ytmp > 0 Then
        aTan2 = pi / 2
    ElseIf Xtmp < 0 And Ytmp < 0 Then
        aTan2 = Atn(Ytmp / Xtmp) - pi
    ElseIf Xtmp = 0 And Ytmp < 0 Then
        aTan2 = -pi / 2
    End If
End Function

Kamis, 31 Juli 2014

View Neighbor Dengan Mapbasic

Post yg ini sih intinya mw ngebahas gmn caranya (step2 dan mapbasic code nya) utk menampilkan neighbor baik itu bothway, oneway incoming, dan oneway outgoing, serta undefined neighbor dari suatu cell seperti yg ada di blog saya yg ini. Intinya sih collect data dari table Nbr, trus dibikin deh garis2 relasinya.

Step2nya yg saya ngerti dan saya pke sih gini :
  1. Join table data cell (Data_3G_Cell) dgn Nbr 3G 3G (Nbr_3G3G). Join dilakukan 2x, pertama utk mendapatkan outgoing data (Source Nbr adalah selected object) dan disimpan sementara di qRel1, lalu yg kedua utk mendapatkan incoming data (Target Nbr adalah selected object) dan disimpan sementara di qRel2. Kedua hasil datanya disimpan di table lain, kita kasi nama aja tmpRel.
  2. Looping qRel1 juga qRel2 utk proses pembuatan object antenna dan garis neighbor nya, sesuai dengan style yg sudah kita define.
  3. Create table tmpObj utk object antenna sesuai dgn object yg sudah di compile di Step 2 dan update table tmpRel utk data InOut_Att ambil dari NCell data (SHO_NCell).
  4. Jika Show Undefined = True, maka harus dicari dari table SHO_NCell yg attempt nya tinggi (melebihi threshold) tp tidak ada di tmpRel. Datanya kemudian ditaro di table tmpRel juga.
  5. Final proses penggambaran object antenna dan relasi.
Puyeng yak baca step2 di atas klo pke bahasa sendiri? huehehe.. Mungkin lebih bs ngerti klo liat mapbasic code nya langsung.

Step 1 :
'Outgoing from selected Object
select Source,Target,SHO_Att,RNC_CellID,Longitude,Latitude,Azimuth,"I=xxxxxxxxxxxxx; O=xxxxxxxxxxxxx" "InOut_Att",Data_3G_Cell.Obj "antObj" 
from tmpNbr_3G3G,Data_3G_Cell 
where tmpNbr_3G3G.Source=selObject     'selObject = RNC_CellID object yg diselect dari table Data_3G_Cell
and tmpNbr_3G3G.Target=Data_3G_Cell.RNC_CellID
and Data_3G_Cell.Carrier=sSelectedCarrier     'sSelectedCarrier = carrier dari selObject
into qRel1 noselect

Commit Table qRel1 As myAppDir + "Table\tmpRel.TAB" TYPE NATIVE Charset "WindowsLatin1"
Open Table myAppDir + "Table\tmpRel.TAB" Interactive
sTableRel_tmp = PathToTableName$(myAppDir + "Table\tmpRel.TAB")

'Incoming to selected Object
select Source,Target,SHO_Att,RNC_CellID,Longitude,Latitude,Azimuth,"I=xxxxxxxxxxxxx; O=xxxxxxxxxxxxx" "InOut_Att",Data_3G_Cell.Obj "antObj" 
from tmpNbr_3G3G,Data_3G_Cell 
where tmpNbr_3G3G.Target=selObject     'selObject = RNC_CellID object yg diselect dari table Data_3G_Cell
and tmpNbr_3G3G.Source=Data_3G_Cell.RNC_CellID 
and Data_3G_Cell.Carrier=sSelectedCarrier     'sSelectedCarrier = carrier dari selObject
into qRel2 noselect

Insert Into sTableRel_tmp ( COL1, COL2, COL3, COL4, COL5, COL6, COL7, COL8) Select COL1, COL2, COL3, COL4, COL5, COL6, COL7, COL8 From qRel2
Commit table sTableRel_tmp

Step 2 :
do while not EOT(qRel1)
inputAnt(iLoop)=qRel1.antObj
ant=inputAnt(iLoop)
sourceId=qRel1.Source
targetId=qRel1.Target
tx=centroidx(ant)
ty=centroidy(ant)

select count(*) from sTableRel_tmp where Source=targetId and Target=sourceId into qBoth noselect
if qBoth.Count > 0 then 'bothway
Create Line into Variable rel (sx,sy) (tx,ty) Pen pPenTargetBoth
antColor=bBrushTargetBoth
else 'outgoing one way
Create Line into Variable rel (sx,sy) (tx,ty) Pen pPenTargetOut
antColor=bBrushTargetOut
end if

close table qBoth
Alter Object inputAnt(iLoop) Info OBJ_INFO_BRUSH, antColor
tmpSourceCell(iLoop)=sourceId
tmpTargetCell(iLoop)=targetId
inputRel(iLoop)=rel
iSelTotalNbr=iSelTotalNbr+1
iLoop=iLoop+1
fetch next from qRel1
loop

do while not EOT(qRel2)
inputAnt(iLoop)=qRel2.antObj
ant=inputAnt(iLoop)
sourceId=qRel2.Source
targetId=qRel2.Target
tx=centroidx(ant)
ty=centroidy(ant)

select count(*) from sTableRel_tmp where Source=targetId and Target=sourceId into qBoth noselect
if qBoth.Count = 0 then
Create Line into Variable rel (sx,sy) (tx,ty) Pen pPenTargetInc
antColor=bBrushTargetInc
Alter Object inputAnt(iLoop) Info OBJ_INFO_BRUSH, antColor
tmpSourceCell(iLoop)=targetId
tmpTargetCell(iLoop)=sourceId
inputRel(iLoop)=rel
iLoop=iLoop+1
end if

close table qBoth
fetch next from qRel2
loop

Step 3 dan 4 :
Create Table tmpObj
(RNC_CellID Char(12))
File myAppDir + "Table\tmpObj.TAB"
Create Map For tmpObj CoordSys Earth
Add Map Window FrontWindow()  Auto Layer tmpObj 

Update sTableRel_tmp Set Obj = CreatePoint(0,0)
Commit table sTableRel_tmp

Set Map Window FrontWindow()  Layer tmpObj Display Off
Set Map Window FrontWindow()  Layer sTableRel_tmp Display Off

for i=1 to (iLoop-1)
insert into tmpObj (RNC_CellID, Obj) values (tmpTargetCell(i),inputAnt(i))

if i > 1 then
select * from sTableRel_tmp where Source=tmpSourceCell(i) and Target=tmpTargetCell(i) into qUpdate noselect
If  TableInfo(qUpdate,8) = 0 Then
close table qUpdate
select * from sTableRel_tmp where Source=tmpTargetCell(i) and Target=tmpSourceCell(i) into qUpdate noselect
end if

update qUpdate set Obj=inputRel(i)
close table qUpdate
end if
next

Commit table sTableRel_tmp
Commit table tmpObj
select * from SHO_NCell where Source=selObject into qNCell1 noselect
select * from SHO_NCell where Target=selObject into qNCell2 noselect

Commit Table qNCell1 As myAppDir + "Table\tmpNCell.TAB" TYPE NATIVE Charset "WindowsLatin1"
Open Table myAppDir + "Table\tmpNCell.TAB" Interactive
sTableNCell_tmp = PathToTableName$(myAppDir + "Table\tmpNCell.TAB")
Insert Into sTableNCell_tmp ( COL1, COL2, COL3) Select COL1, COL2, COL3 From qNCell2
Commit table sTableNCell_tmp

if iShowUndefined=1 then
'alter table add ismatched column
alter table sTableNCell_tmp (add isMatched integer)
commit table sTableNCell_tmp
update sTableNCell_tmp set isMatched=0
commit table sTableNCell_tmp

select * from tmpNCell,tmpRel where tmpNCell.Source=tmpRel.Source and tmpNCell.Target=tmpRel.Target into qUpdate noselect
update qUpdate set isMatched=1
commit table sTableNCell_tmp
close table qUpdate

select * from tmpNCell,tmpRel where tmpNCell.Source=tmpRel.Target and tmpNCell.Target=tmpRel.Source into qUpdate noselect
update qUpdate set isMatched=1
commit table sTableNCell_tmp
close table qUpdate

if sCarrierTarget3G="" then
select Source,Target,SHO_Att,RNC_CellID,Longitude,Latitude,Azimuth,"I=xxxxxxxxxxxxx; O=xxxxxxxxxxxxx" "InOut_Att",Data_3G_Cell.Obj "antObj" 
from tmpNCell,Data_3G_Cell 
where tmpNCell.Source=selObject
and tmpNCell.Target=Data_3G_Cell.RNC_CellID 
and tmpNCell.SHO_Att > fUndefinedAtt 
and tmpNCell.IsMatched=0 
and Data_3G_Cell.Carrier=sSelectedCarrier 
into qUndefinedObj noselect
else
select Source,Target,SHO_Att,RNC_CellID,Longitude,Latitude,Azimuth,"I=xxxxxxxxxxxxx; O=xxxxxxxxxxxxx" "InOut_Att",Data_3G_Cell.Obj "antObj" 
from tmpNCell,Data_3G_Cell 
where tmpNCell.Source=selObject
and tmpNCell.Target=Data_3G_Cell.RNC_CellID 
and tmpNCell.SHO_Att > fUndefinedAtt 
and tmpNCell.IsMatched=0 
and Data_3G_Cell.Carrier=sCarrierTarget3G 
into qUndefinedObj noselect
end if

Insert Into sTableRel_tmp ( COL1, COL2, COL3, COL4, COL5, COL6, COL7, COL8) Select COL1, COL2, COL3, COL4, COL5, COL6, COL7, COL8 From qUndefinedObj
commit table sTableRel_tmp

fetch first from qUndefinedObj
do while not EOT(qUndefinedObj)
undefinedAnt=qUndefinedObj.antObj
undefinedSCell=qUndefinedObj.Source
undefinedTCell=qUndefinedObj.Target
Alter Object undefinedAnt Info OBJ_INFO_BRUSH, bBrushUndefined
insert into tmpObj (RNC_CellID, Obj) values (undefinedTCell,undefinedAnt)

tx=centroidx(undefinedAnt)
ty=centroidy(undefinedAnt)
Create Line into Variable rel (sx,sy) (tx,ty) Pen pPenUndefined

select * from sTableRel_tmp where Source=undefinedSCell and Target=undefinedTCell into qUpdate noselect
update qUpdate set Obj=rel
close table qUpdate
fetch next from qUndefinedObj
loop

commit table tmpObj
commit table sTableRel_tmp
Close Table qUndefinedObj
end if

'loop table sTableRel_tmp to update InOut_Att
select * from sTableRel_tmp into qLoopRel noselect
fetch first from qLoopRel
do while not EOT(qLoopRel)
NCellSource=qLoopRel.Source
NCellTarget=qLoopRel.Target

'in
select * from sTableNCell_tmp where Source=NCellTarget and Target=NCellSource into qIN noselect
NCellIn="In=" + qIN.SHO_Att

'out
select * from sTableNCell_tmp where Source=NCellSource and Target=NCellTarget into qOUT noselect
NCellOut="Out=" + qOut.SHO_Att

NCellInOut=NCellIn + " ; " + NCellOut

select * from sTableRel_tmp where Source=NCellSource and Target=NCellTarget into qUpdateRel noselect
update qUpdateRel set InOut_Att=NCellInOut
close table qUpdateRel
fetch next from qLoopRel
loop

commit table sTableRel_tmp

Step 5 :
Set Map Window FrontWindow()  Layer tmpObj Display Graphic
Set Map Window FrontWindow()  Layer sTableRel_tmp Display Graphic

Set Map Window FrontWindow()  Layer sTableRel_tmp Label Font ("Arial",256,9,255,16777215) With InOut_Att
Set Map Window FrontWindow()  Layer sTableRel_tmp Label Auto On

Untuk Nbr 3G ke 2G dan Nbr 2G ke 2G jg sama pke step2 di atas, cuma nama table data cell, Nbr, dan NCell nya aja yg di ganti. Mudah2an abis liat mapbasic code utk view Nbr dari step 1 ampe step 5 di atas ga tambah puyeng yak :))))

Selasa, 29 Juli 2014

Ngulik Mapbasic (part-3)

Setelah di part sebelumnya kita nyoba2 create point dan ngedit style object pke mapbasic, skrg iseng2annya coba bikin sectoral view dr data cell. Oiya utk yg ini berkaitan dgn project iseng yg skrg lg digarap di blog TelMi Project ini. Data yg dibutuhin standar nya ya cuma unique name, longitude, latitude dan azimuth. Tapi biar data ini nantinya bisa dipake lebih jauh, maka data cell nya dibikin kayak gini aja :

Struktur table data cell

Sectoral view klo di mapinfo bisa kita dapetin dgn mengkombinasi circle, arc, pline, dan region. Circle untuk initial bentuknya, arc untuk bentuk kipas luarnya dgn lebar sesuai beam width, pline untuk mengubah arc menjadi bentuk kipas, dan region sbg final object nya. Ribet ya? Emang.. hahaha.. btw cara ini jg saya dapet googling koq :p

Mapbasic code nya kayak gini :
circ = CreateCircle(centroXObj, centroYObj, (cellRadius/1.60934))
Create Arc into Variable pie (ObjectGeography(circ, 1), ObjectGeography(circ, 2)) (ObjectGeography(circ, 3),
ObjectGeography(circ, 4)) startDir endDir
pie=converttopline(pie) 
alter Object pie Node Add (centroXObj,centroYObj)
pie=converttoregion(pie)
Alter Object pie Info OBJ_INFO_BRUSH, cellStyleColor

Data cell di import dulu lalu di create point. setelah proses create point baru deh dibikin sectoral view nya dgn mapbasic code seperti di atas. Beberapa variable yg dibutuhkan utk create sectoral view dgn metode di atas yaitu :
  1. CentroXObj dan centroYObj adalah nilai dari centroidX dan centroidY object hasil create point (baca di help mapinfo ttg built in function tsb).
  2. cellRadius adalah radius sectoral yg akan kita buat, dalam satuan Km.
  3. startDir dan endDir utk menentukan lebar sektoral view, nilai ini didapat dari (azimuth + beamWidth/2) dan (azimuth - beamWidth/2). Perlu diingat bahwa sudut 0 pada mapinfo berbeda dengan sudut 0 pada panoramic yg dimulai dari utara sehingga disini perlu proses konversi terlebih dahulu.
  4. cellStyleColor adalah brush yg harus kita define terlebih dahulu.
Hasil dari create sectoral view dari data cell 2G dan 3G dengan multiple carrier nya akan seperti gambar ini :

Hasil create sectoral view

Dari gambar di atas terlihat bahwa untuk 1 site yg sama dengan banyak carrier, sectoral view nya tdk teratur, saling tumpang tindih. Kadang carrier-1 posisi di atas, kadang di bawah. Setelah googling kesana-sini ternyata emg di mapinfo tuh utk 1 table yg sama ga ada ordering object layer. Object di render bukan berdasarkan urutan baris data di table, tp berdasarkan density object tsb. Klo kata yg expert sih gini :

"There is no way to permanently control the draw order of objects within a layer.  Layers are the only unit of draw order. Objects are draw in the order they come back from the spatial index and that is determined by the density of objects in an area, the size of the internal blocks and the implementation of the data source (MapInfo native files, MapInfo data stored in a database such as MapInfo SpatialWare or third party vendors such as Oracle where we have absolutely no say over the order). The order is definitely NOT the order in which the data is created and is not in any way related to the Rowids of the records."

Jadi utk ngakalin tampilannya biar cakep, bisa dibikin table2 yg hanya utk sekedar view aja, itu dipisah utk tiap2 carriernya.
Ampe disini pembahasan ttg object2an nya udahan aja. Postingan berikutnya kita coba bahas ttg gmn mapbasic ini bs ngebantu kita dlm hal keperluan optimasi - khususnya dlm neighboring, yg juga merupakan detil Project TelMi.