Implementasi Mobile Tracking Menggunakan Metode Ant Colony Optimization Dan Google Maps Api
LISTING PROGRAM
1. Halaman Admin
<!DOCTYPE html PUBLIC "-//W3C//DTD
XHTML
1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas- microsoft-com:vml" itemscope itemtype="http://schema.org/Product"> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <meta itemprop="name" content="OptiMap"> <meta itemprop="description" content="Fastest roundtrip solver with ACO"> <title>SANJAYA - Ant Colony Optimazion for Google Maps API</title> <link rel="stylesheet" href="<?php echo base_url().'media/style.css'; ?>" type="text/css" media="screen"> <link rel="stylesheet" href="<?php echo base_url().'media/print.css'; ?>" type="text/css" media="print"> <link type="text/css" href="<?php echo base_url().'media/jquery-ui- 1.8.16.custom.css'; ?>" rel="stylesheet" /> <script type="text/javascript" src="<?php echo base_url().'media/jquery.min.js'; ?>"></script> <script type="text/javascript" src="<?php echo base_url().'media/jquery-ui.min.js'; ?>"></script> <meta name="viewport" content="initial-scale=1.0, user-scalable=no" /> <script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript" src="<?php echo base_url().'media/BpTspSolver.js'; ?>"></script> <script type="text/javascript" src="<?php echo base_url().'media/tsp.js'; ?>"></script> <script type="text/javascript" src="<?php echo base_url().'media/directions-export.js'; ?>"></script> <script type="text/javascript"> </script> <script type="text/javascript"> jQuery.noConflict(); function onBodyLoad() { google.load("maps", "3", {callback: init, other_params:"sensor=false"}); } function loadAtStart(lat, lng, zoom) { var center = new google.maps.LatLng(lat, lng); initMap(center, zoom, document.getElementById("map")); directionsPanel = document.getElementById("my_textual_div"); tsp = new BpTspSolver(gebMap, directionsPanel); tsp.setDirectionUnits("m");
<?php foreach ($mobile->result() as $row){?> tsp.addWaypoint(new google.maps.LatLng(<?php echo "$row- >lat"; ?>, <?php echo "$row->long"; ?>));
<?php }?> google.maps.event.addListener(tsp.getGDirectionsService(), "error", function() {
- alert("Request failed: " reasons[tsp.getGDirectionsService().getStatus().code]); }); } function init() { if (google.loader.ClientLocation != null) { latLng = new google.maps.LatLng(google.loader.ClientLocation.latitude, google.loader.ClientLocation.longitude); loadAtStart(google.loader.ClientLocation.latitude, google.loader.ClientLocation.longitude, 8);
} else { loadAtStart(3.5855598,98.67395720000002, 14); }
} function toggle(divId) { var divObj = document.getElementById(divId); if (divObj.innerHTML == "") {
- divObj.innerHTML = document.getElementById(divId "_hidden").innerHTML; document.getElementById(divId + "_hidden").innerHTML = ""; } else {
- document.getElementById(divId "_hidden").innerHTML = divObj.innerHTML; divObj.innerHTML = ""; } } jQuery(function() { jQuery( "#accordion" ).accordion({ collapsible: true, autoHeight: false, clearStyle: true
}); jQuery("input:button").button(); jQuery("#dialogProgress" ).dialog({ height: 140, modal: true, autoOpen: false
}); jQuery("#progressBar").progressbar({ value: 0 }); jQuery("#dialogTomTom" ).dialog({ height: 480, width: 640, modal: true, autoOpen: false
}); jQuery("#dialogGarmin" ).dialog({ height: 480, width: 640, modal: true, autoOpen: false }); }); (function() { var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true; po.src = 'https://apis.google.com/js/plusone.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s); })(); </script> </head> <body onLoad="onBodyLoad()"> <h2>Ant Colony Optimization - Untuk Menentukan Jalur Terdekat</h2> <table class='mainTable'> <tr> <td class='left' style='vertical-align: top'> <div id="leftPanel"> <div id="accordion" style='width: 300pt'> <h3><a href="#" class='accHeader'>Tujuan</a></h3> <div> <form name="address" onSubmit="clickedAddAddress(); return false;"> Tambah alamat tujuan : <table> <tr> <td><input name="addressStr" type="text"></td> <td><input type="button" value="Add!" onClick="clickedAddAddress()"></td> </tr> </table> </form> Atau <a href="#" onClick="toggle('bulkLoader'); document.listOfLocations.inputList.focus(); document.listOfLocations.inputList.select(); return false;"> Berapa Alamat or (lat, lng)</a>. <div id="bulkLoader"></div> </div> <h3><a href="#" class='accHeader'>Pilihan Jalur</a></h3> <div> <form name="travelOpts"> <input id="walking" type="checkbox"/> Walking (Jalan kaki)<br> <input id="bicycling" type="checkbox"/> Bicycling (Naik sepeda)<br> <input id="avoidHighways" type="checkbox"/> Avoid highways (Hindari jalan raya)<br> <input id="avoidTolls" type="checkbox"/> Avoid toll roads (Hindari jalan tol) </form> </div>
<h3><a href="#" class='accHeader'>Export</a></h3> <div> <div id="exportGoogle"></div> <div id="exportDataButton"></div> <div id="exportData"></div> <div id="exportLabelButton"></div> <div id="exportLabelData"></div> <div id="exportAddrButton"></div> <div id="exportAddrData"></div> <div id="exportOrderButton"></div> <div id="exportOrderData"></div> <div id="garmin"></div> <div id="tomtom"></div> <div id="durations" class="pathdata"></div> <div id="durationsData"></div> </div> <h3><a href="#" class='accHeader'>Edit Route</a></h3> <div> <div id="routeDrag"></div> <div id="reverseRoute"></div> </div> <h3><a href="#" class='accHeader'>Mobile Tracking</a></h3> <div>
<input id='button3' class="calcButton" type='button' value='Lacak User' onClick='TrackMobile()'> <input id="button1" class="calcButton" type="button" value="Hitung Perjalanan TSP" onClick="directions(0, document.forms['travelOpts'].walking.checked, document.forms['travelOpts'].bicycling.checked, document.forms['travelOpts'].avoidHighways.checked, document.forms['travelOpts'].avoidTolls.checked)">
<input id="button2" class="calcButton" type="button" value="Hitung Perjalanan dari A - Z" onClick="directions(1, document.forms['travelOpts'].walking.checked, document.forms['travelOpts'].bicycling.checked, document.forms['travelOpts'].avoidHighways.checked, document.forms['travelOpts'].avoidTolls.checked)"> </div> </div> <input id='button3' class="calcButton" type='button' value='Data Clinet' onClick="popup('<?php echo base_url() ?>adminweb/data', 'Win1', 1500, 600); return false"> <input id='button3' class="calcButton" type='button' value='Ulangi Lagi' onClick='startOver()'> <input id='button3' class="calcButton" type='button' value='Refresh Halaman' onClick='RefreshPage()'> <input id='button3' class="calcButton" type='button' value='Pengujian Javascript' onClick='testJS()'> <input id='button3' class="calcButton" type='button' value='About' onClick="popup('http://www.sanjayamediatama.com/templates/default/img /index.html', 'Win1', 600, 600); return false"> <input id='button3' class="calcButton" type='button' value='Logout' onclick="window.location='<?php echo base_url() ?>adminweb/logout';"> </td> <td class='right' style='vertical-align: top'> <?php echo ! empty($kanan) ? $this->load->view($kanan) : ''; ?> </td> </tr>
</table> <!-- Hidden stuff --> <div id="bulkLoader_hidden" style="visibility: hidden;"> <form name="listOfLocations" onSubmit="clickedAddList(); return false;"> <textarea name="inputList" rows="10" cols="70">Isikan tujuan perbarisnya</textarea><br> <input type="button" value="Tambahkan daftar Tujuan" onClick="clickedAddList()"> </form></div> <div id="exportData_hidden" style="visibility: hidden;"></div> <div id="exportLabelData_hidden" style="visibility: hidden;"></div> <div id="exportAddrData_hidden" style="visibility: hidden;"></div> <div id="exportOrderData_hidden" style="visibility: hidden;"></div> <div id="durationsData_hidden" style="visibility: hidden;"></div> <div id="dialogProgress" title="Hitung perjalanan..."> <div id="progressBar"></div> </div> <div id="dialogTomTom" title="Export to TomTom"> <iframe name='tomTomIFrame' style='width: 580px; height: 400px'></iframe> </div> <div id="dialogGarmin" title="Export to Garmin"> <iframe name='garminIFrame' style='width: 580px; height: 400px'></iframe> </div> </body> </html>
2. Admin Controller
<?php class Adminweb extends CI_Controller { function __construct(){ parent::__construct();
$this->load->model('M_mobile', '', TRUE); } function index(){
$this->load->view('loginadmin'); } function aco(){
$this->auth->restrict_admin(); $data['mobile'] = $this->M_mobile-
>all_track(); $data['kanan'] = "map"; $this->load->view('adminweb',$data);
} function data(){ $data['mobile'] = $this->M_mobile-
>all_track();
$data['query'] = $this->M_mobile- >data_client();
$data['kanan'] = "data"; $this->load->view('adminweb',$data);
} /**
- Pindah ke halaman update
- / function edit($id_client) {
$data['mobile'] = $this->M_mobile- >all_track();
$client = $this->M_mobile- >get_client_by_id($id_client)->row();
$data['default']['id_client'] = $client->id_client;
$data['default']['nama'] = $client->nama;
$data['default']['username'] = $client->username;
$data['default']['password'] = $client->password;
$data['default']['jenis_kelamin'] = $client->jenis_kelamin;
$data['default']['no_hp'] = $client->no_hp;
$data['default']['alamat'] = $client->alamat;
$data['default']['aktif'] = $client->aktif;
$data['default']['lat'] = $client->lat;
$data['default']['long'] = $client->long;
$data['kanan'] = "editclient"; $this->load->view('adminweb',$data);
} function proses_simpan(){ $id_client = $this->input-
>post('id_client'); $password = $this->input->post('password'); if (empty($password)){ $profile = array(
'username' => $this->input->post('username'),
'nama' => $this->input->post('nama'),
'jenis_kelamin' => $this->input->post('jenis_kelamin'),
'no_hp' => $this->input->post('no_hp'),
'aktif' => $this->input->post('aktif'),
'alamat' => $this->input->post('alamat')
); }else{ $profile = array(
'username' => $this->input->post('username'),
'password' => md5($password), 'nama'
=> $this->input->post('nama'), 'jenis_kelamin' =>
$this->input->post('jenis_kelamin'), 'no_hp'
=> $this->input->post('no_hp'), 'aktif'
=> $this->input->post('aktif'), 'alamat' =>
$this->input->post('alamat') );
} $this->M_mobile-
>update_profile($id_client,$profile); $this->session-
>set_flashdatắmessagé, 'profile berhasil diupdate!'); redirect('adminweb/data'); } /**
- Hapus data
- / function hapus($id_data) {
$this->M_mobile->hapus($id_data); redirect('adminweb/data'); } /**
- Memproses login
- / function proses_login() {
$username = $this->input->post('username'); $password = $this->input->post('password'); $success = $this->auth-
>admin_login($username,$password); if($success) { redirect('adminweb/aco'); } else {
$this->session- >set_flashdatắmessagé, 'Maaf, username dan atau password Anda salah, Atau Account anda sedang diblokir, silahkan Hubungi administrator untuk mengaktifkan kembali!!'); redirect('adminweb');
} } /**
- Memproses logout
- / function logout() {
$this->session->sess_destroy(); redirect('adminweb', 'refresh'); }
}
3. Halaman User
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <!-- <script type="text/javascript" src="jquery- 1.6.2.min.js"></script> --> <script type="text/javascript" src="<?php echo base_url().'media/jquery-1.7.2.js'; ?>"></script> <meta name="viewport" content="initial-scale=1.0, user-scalable=no" /> <style> html{ height:100%;
} body{ height:100%;
} #canvas{ height:80%; }
</style> <title>Peta Dinamis Pertamaku</title> <script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?key=AIzaSyCeCAhmBV1aJRpEy
TpQzwZV-NS_zIfGdSE&sensor=false&language=id"></script> <script type="text/javascript">
//Mendeklarasikan Array untuk menampung marker dan balloon yang ada sehiingga mempermudah saat memanggilnya kembali var markers = new Array(); var infowindows = new Array(); var refreshId = setInterval(function()
{ $('#tracking').fadeOut("slow").load('<?php echo base_url(); ?>index.php/tracking/proses').fadeIn("slow");
}, 1000); var refreshId2 = setInterval(function() {
$('#koordinat').fadeOut("slow").load('<?php echo base_url(); ?>index.php/tracking/koordinat').fadeIn("slow"); }, 1000); var refreshId3 = setInterval(function(){ navigator.geolocation.getCurrentPosition(foundLocation, noLocation); }, 10000); function noLocation() { alert("Sensor GPS tidak ditemukan");
} function foundLocation(position) { var lat = position.coords.latitude; var lon = position.coords.longitude; $('#koordinat2').fadeOut("slow").html("Latitude: " + lat
- "<br>Longitude: " + lon).fadeIn("slow"); var uri = "<?php echo base_url().'index.php/tracking/simpanlokasi'; ?>";
$.ajax({ type: 'POST', async: false, dataType: "html", url: uri, data: "lat="+lat+"&long="+lon, success: function(data) { }
}); } /* Melakukan refresh setiap beberapa detik sekali */ var refreshId4 = setInterval(function(){updatedata();}, 12000); function updatedata(){ var lat = 0; var long = 0; for(var i=0;i<markers.length;i++){ var uri = "<?php echo base_url().'index.php/tracking/ambildata1'; ?>"; $.ajax({ type: 'POST', async: false, dataType: "html", url: uri, data: "id="+i, success: function(data) { lat=data; }
}); var uri = "<?php echo base_url().'index.php/tracking/ambildata2'; ?>";
$.ajax({ type: 'POST', async: false, dataType: "html", url: uri, data: "id="+i, success: function(data) { long = data; }
}); var myLatLng = new google.maps.LatLng(lat,long); markers[i].setPosition(myLatLng); infowindows[i].setPosition(myLatLng);
} } function initialize(){ var myLatLng = new google.maps.LatLng(3.5674094,
98.66089480000005); var myOptions = { zoom: 14, center:myLatLng, mapTypeId: google.maps.MapTypeId.ROADMAP
} map = new google.maps.Map( document.getElementById('canvas'),myOptions);
<?php foreach ($tampil->result() as $row){?> var marker= new google.maps.Marker({ position:new google.maps.LatLng(<?php echo
"$row->lat"; ?>, <?php echo "$row->long"; ?>), map:map, title:"Saya disini <?php echo "$row->nama";
?>" }); marker.setIcon({ url: "http://4.bp.blogspot.com/- hNcYtcecKTs/T82Sd4ZNn7I/AAAAAAAABWc/l4P-UrOR4rg/s400/Blackberry.png", scaledSize: new google.maps.Size(30, 24) , anchor: new google.maps.Point(15, 12)}); markers.push(marker); var infowindow= new google.maps.InfoWindow({ content:"<img src='http://www.sanjayamediatama.com/templates/default/img/trackaco.p ng' width='100' align='left' /><?php echo "$row->nama <br> $row- >alamat<br>HP : $row->no_hp" ?>", size: new google.maps.Size(50,50), position:new google.maps.LatLng(<?php echo
"$row->lat"; ?>, <?php echo "$row->long"; ?>) }); infowindow.open(map); infowindows.push(infowindow);
<?php }?>
} </script> </head> <div id="tracking"></div> <div id="koordinat"></div> <?php
$message = $this->session->flashdatắmessagé); echo $message == '' ? '' : '<p id="message" align="center">' . $message . '</p>'; ?> <body onLoad="initialize()"> <div id="canvas"></div> <div id="koordinat2"></div> <?php echo anchor('tracking/profile', 'Edit Profile', 'title="Keluar dari Halaman"');?> | <?php echo anchor('client/logout', 'LogOut', 'title="Keluar dari Halaman"');?> </body> </html>
4. User Controller
<?php class Client extends CI_Controller { function __construct(){ parent::__construct();
$this->load->model('M_mobile', '', TRUE); } public function index() { if($this->auth->is_logged_in() == false)
{ $this->load->view('login');
} else { redirect('tracking'); }
} function login(){ $this->load->view('login');
} function daftar(){ $this->load->view('daftar');
} function proses_daftar(){ $password = $this->input->post('password'); $username = $this->input->post('username'); if (empty($password) || empty($username)){
$this->session- >set_flashdatắmessagé, 'username atau password masih kosong!'); redirect('client/daftar');
}else{ $daf = array(
'id_client' => $this->input->post('id_client'),
'username' => $username,
'password' => md5($password), 'nama'
=> $this->input->post('nama'), 'jenis_kelamin' =>
$this->input->post('jenis_kelamin'), 'no_hp'
=> $this->input->post('no_hp'), 'aktif'
=> $this->input->post('aktif'), 'alamat' =>
$this->input->post('alamat') ); $this->M_mobile-
>tambah_client($daf); }
$this->session- >set_flashdatắmessagé, 'data berhasil disimpan, tunggu max 2x24 jam. data akan segera diaktifkan!'); redirect('client/login');
} /**
- Memproses login
- / function proses_login() {
$username = $this->input->post('username'); $password = $this->input->post('password'); $success = $this->auth-
>do_login($username,$password); if($success) { redirect('tracking'); } else {
$this->session- >set_flashdatắmessagé, 'Maaf, username dan atau password Anda salah, Atau Account anda sedang diblokir, silahkan Hubungi administrator untuk mengaktifkan kembali!!'); redirect('client');
} } /**
- Memproses logout
- / function logout() {
$this->session->sess_destroy(); redirect('client/login', 'refresh'); }
}
5. Tracking Controller
$this->load->model('M_mobile', '', TRUE); } function index(){
$data['default']['alamat'] = $client->alamat;
'no_hp' => $this->input->post('no_hp'),
'jenis_kelamin' => $this->input->post('jenis_kelamin'),
'nama' => $this->input->post('nama'),
'username' => $this->input->post('username'),
$password = $this->input->post('password'); if (empty($password)){ $profile = array(
$id_client = $this->input- >post('id_client');
$this->load->view('profile',$data); } function proses_simpan(){
$data['default']['no_hp'] = $client->no_hp;
$data['tampil'] = $this->M_mobile- >get_track();
<?php class Tracking extends CI_Controller { function __construct(){ parent::__construct();
$data['default']['nama'] = $client->nama;
$data['default']['password'] = $client->password;
$data['default']['username'] = $client->username;
$data['default']['id_client'] = $client->id_client;
$client = $this->M_mobile- >get_client_by_id($this->session->userdatắid_client'))- >row();
$this->load->view('track',$data); } function profile(){
$data['default']['jenis_kelamin'] = $client->jenis_kelamin;
'alamat' => $this->input->post('alamat')
$lat = $this->input->post('lat'); $long = $this->input->post('long'); $tangal = date("Y-m-d H:i:s"); $session_login = $this->session-
>valid_lokasi($session_login)->num_rows(); if($jml == 0){ $this->M_mobile-
); $jml = $this->M_mobile-
'session_login' => $session_login
'time' => $tangal,
'long' => $long,
'lat' => $lat,
'id_client' => $id_client,
'id_track' => $this->input->post('id_track'),
>userdatắsession_id'); $latlong = array(
$id_client = $this->session- >userdatắid_client');
); }else{ $profile = array(
>set_flashdatắmessagé, 'profile berhasil diupdate!'); redirect('tracking'); } function simpanlokasi(){
>update_profile($id_client,$profile); $this->session-
} $this->M_mobile-
$this->input->post('alamat') );
=> $this->input->post('no_hp'), 'alamat' =>
$this->input->post('jenis_kelamin'), 'no_hp'
=> $this->input->post('nama'), 'jenis_kelamin' =>
'password' => md5($password), 'nama'
'username' => $this->input->post('username'),
>track_lokasi($latlong);
} $this->M_mobile-
>update_lokasi($id_client,$lat,$long); } function ambildata1(){
$id = $this->input->post('id'); $lat = $this->M_mobile->get_LatLong($id)->row(); echo $lat->lat;
} function ambildata2(){ $id = $this->input->post('id'); $long = $this->M_mobile->get_LatLong($id)->row(); echo $long->long;
} function proses(){ echo "tracking location processing ...";
} function koordinat(){ $this->load->view('koordinat');
} }
6. Ant Colony
(function() { var tsp; // singleton var gebMap; // The map DOM object var directionsPanel; // The driving directions DOM object var gebDirectionsResult; // The driving directions returned from GMAP API var gebDirectionsService; var gebGeocoder; // The geocoder for addresses var maxTspSize = 100; // A limit on the size of the problem, mostly to save Google servers from undue load. var maxTspBF = 0; // Max size for brute force, may seem conservative, but ma var maxTspDynamic = 15; // Max size for brute force, may seem conservative, but many browsers have limitations on run-time. var maxSize = 10; // Max number of waypoints in one Google driving directions request. var maxTripSentry = 2000000000; // Approx. 63 years., this long a route should not be reached... var avoidHighways = false; // Whether to avoid highways. False by default. var avoidTolls = false; // Whether to avoid toll roads. False by default. var travelMode; var distIndex; var waypoints = new Array(); var addresses = new Array(); var GEO_STATUS_MSG = new Array(); var DIR_STATUS_MSG = new Array(); var labels = new Array(); var addr = new Array(); var wpActive = new Array(); var addressRequests = 0; var addressProcessing = false; var requestNum = 0; var currQueueNum = 0; var wayArr; var legsTmp; var distances; var durations; var legs; var dist; var dur; var visited; var currPath; var bestPath; var bestTrip; var nextSet; var numActive; var costForward; var costBackward; var improved = false; var chunkNode; var okChunkNode; var numDirectionsComputed = 0; var numDirectionsNeeded = 0; var cachedDirections = false; var requestLimitWait = 1000; var fakeDirResult; // Object used to store travel info like travel mode etc. Needed for route renderer. var onSolveCallback = function(){}; var onProgressCallback = null; var originalOnFatalErrorCallback = function(tsp, errMsg) { alert("Request failed: " + errMsg); } var onFatalErrorCallback = originalOnFatalErrorCallback; var doNotContinue = false; var onLoadListener = null; var onFatalErrorListener = null; var directionunits; /* Computes a near-optimal solution to the TSP problem,
- using Ant Colony Optimization and local optimization * in the form of k2-opting each candidate route.
- Run time is O(numWaves * numAnts * numActive ^ 2) for ACO
- and O(numWaves * numAnts * numActive ^ 3) for rewiring? >if mode is 1, we start at node 0 and end at node numActive-1.
- / function AntColony(mode) { var alfa = 0.1; // Pentingnya jalan sebelumnya var beta = 2.0; // Pentingnya jangka waktu var rho = 0.1; // Tingkat pembusukan jalan feromon
} } var lastNode = 0; var startNode = 0; var numSteps = numActive - 1; var numValidDests = numActive; if (mode == 1) { lastNode = numActive - 1; numSteps = numActive - 2; numValidDests = numActive - 1; }
/*perhitungan ACO sesuai jumlah semut dan siklus*/ for (var wave = 0; wave < numWaves; ++wave) { for (var ant = 0; ant < numAnts; ++ant) { var curr = startNode; var currDist = 0; for (var i = 0; i < numActive; ++i) { visited[i] = false; } currPath[0] = curr; for (var step = 0; step < numSteps; ++step) { visited[curr] = true; var cumProb = 0.0; /* probabiitas semut*/ for (var next = 1; next < numValidDests; ++next)
{ if (!visited[next]) { prob[next] = Math.pow(pher[curr][next], alfa) * Math.pow(dur[curr][next], 0.0 - beta); cumProb += prob[next]; }
} /*Mengambil bilangan random untuk menentukan kota yg akan ditempuh selanjutnya*/ var guess = Math.random() * cumProb; var nextI = -1; for (var next = 1; next < numValidDests; ++next)
{ if (!visited[next]) { nextI = next; guess -= prob[next]; if (guess < 0) { nextI = next; break;
} }
} currDist += dur[curr][nextI]; currPath[step+1] = nextI; curr = nextI; } currPath[numSteps+1] = lastNode; currDist += dur[curr][lastNode]; // k2-rewire: var lastStep = numActive; if (mode == 1) { lastStep = numActive - 1; } var changed = true; var i = 0; while (changed) { changed = false; for (; i < lastStep - 2 && !changed; ++i) { var cost = dur[currPath[i+1]][currPath[i+2]]; var revCost = dur[currPath[i+2]][currPath[i+1]]; var iCost = dur[currPath[i]][currPath[i+1]]; var tmp, nowCost, newCost; for (var j = i+2; j < lastStep && !changed;
- j) {
- nowCost = cost iCost dur[currPath[j]][currPath[j+1]];
- newCost = revCost dur[currPath[i]][currPath[j]] + dur[currPath[i+1]][currPath[j+1]]; if (nowCost > newCost) { currDist += newCost - nowCost; // Membalikkan ruas jalan terpisah for (var k = 0; k < Math.floor((j- i)/2); ++k) { tmp = currPath[i+1+k]; currPath[i+1+k] = currPath[j-k]; currPath[j-k] = tmp; } changed = true;
- i; } cost += dur[currPath[j]][currPath[j+1]]; revCost += dur[currPath[j+1]][currPath[j]]; }
} } if (currDist < bestTrip) { bestPath = currPath; bestTrip = currDist; } /*Local Update And Decay Pheromone*/ for (var i = 0; i <= numSteps; ++i) { nextPher[currPath[i]][currPath[i+1]] += (bestTrip
- bestTrip) / (numAnts (currDist * asymptoteFactor - asymptoteFactor * bestTrip));
} }
/*Apply global pheromone update */ for (var i = 0; i < numActive; ++i) { for (var j = 0; j < numActive; ++j) { pher[i][j] = pher[i][j] * (1.0 - rho) + rho * nextPher[i][j]; nextPher[i][j] = 0.0;
} }
} } function makeLatLng(latLng) { return(latLng.toString().substr(1,latLng.toString().length-2)); } function makeDirWp(latLng, address) { if (address != null && address != "") return ({ location: address, stopover: true }); return ({ location: latLng, stopover: true }); } function getWayArr(curr) { var nextAbove = -1; for (var i = curr + 1; i < waypoints.length; ++i) { if (wpActive[i]) { if (nextAbove == -1) { nextAbove = i; } else { wayArr.push(makeDirWp(waypoints[i], addresses[i])); wayArr.push(makeDirWp(waypoints[curr], addresses[curr])); }
} } if (nextAbove != -1) { wayArr.push(makeDirWp(waypoints[nextAbove], addresses[nextAbove])); getWayArr(nextAbove); wayArr.push(makeDirWp(waypoints[curr], addresses[curr])); } } function getDistTable(curr, currInd) { var nextAbove = -1; var index = currInd; for (var i = curr + 1; i < waypoints.length; ++i) { if (wpActive[i]) { index++; if (nextAbove == -1) { nextAbove = i; } else { legs[currInd][index] = legsTmp[distIndex]; dist[currInd][index] = distances[distIndex]; dur[currInd][index] = durations[distIndex++]; legs[index][currInd] = legsTmp[distIndex]; dist[index][currInd] = distances[distIndex]; dur[index][currInd] = durations[distIndex++]; }
} } if (nextAbove != -1) { legs[currInd][currInd+1] = legsTmp[distIndex]; dist[currInd][currInd+1] = distances[distIndex]; dur[currInd][currInd+1] = durations[distIndex++]; getDistTable(nextAbove, currInd+1); legs[currInd+1][currInd] = legsTmp[distIndex]; dist[currInd+1][currInd] = distances[distIndex]; dur[currInd+1][currInd] = durations[distIndex++]; } } // membuat jalur function directions(mode) { if (cachedDirections) { // Bypass Google directions lookup if we already have the distance and duration matrices.
// Melewati jalur pencarian arah Google jika kita sudah memiliki matriks jarak dan durasi. doTsp(mode); } wayArr = new Array(); numActive = 0; numDirectionsComputed = 0; for (var i = 0; i < waypoints.length; ++i) { if (wpActive[i]) ++numActive; } numDirectionsNeeded = numActive * (numActive - 1); for (var i = 0; i < waypoints.length; ++i) { if (wpActive[i]) { wayArr.push(makeDirWp(waypoints[i], addresses[i])); getWayArr(i); break;
} } // Roundtrip if (numActive > maxTspSize) { alert("Too many locations! You have " + numActive + ", but max limit is " + maxTspSize); } else { legsTmp = new Array(); distances = new Array(); durations = new Array(); chunkNode = 0; okChunkNode = 0; if (typeof onProgressCallback == 'function') { onProgressCallback(tsp); } nextChunk(mode); } } function nextChunk(mode) { // alert("nextChunk"); chunkNode = okChunkNode; if (chunkNode < wayArr.length) { var wayArrChunk = new Array(); for (var i = 0; i < maxSize && i + chunkNode < wayArr.length;
- i) { wayArrChunk.push(wayArr[chunkNode+i]);
} var origin; var destination; origin = wayArrChunk[0].location; destination = wayArrChunk[wayArrChunk.length- 1].location; var wayArrChunk2 = new Array(); for (var i = 1; i < wayArrChunk.length - 1; i++) { wayArrChunk2[i-1] = wayArrChunk[i]; } chunkNode += maxSize; if (chunkNode < wayArr.length-1) { chunkNode--; } var myGebDirections = new google.maps.DirectionsService(); myGebDirections.route({ origin: origin, destination: destination, waypoints: wayArrChunk2, avoidHighways: avoidHighways, avoidTolls: avoidTolls, unitSystem: directionunits, travelMode: travelMode }, function(directionsResult, directionsStatus) { if (directionsStatus == google.maps.DirectionsStatus.OK) { requestLimitWait = 1000; //alert("Request completed!"); // Save legs, distances and durations fakeDirResult = directionsResult; for (var i = 0; i < directionsResult.routes[0].legs.length;
- i) {
- numDirectionsComputed; legsTmp.push(directionsResult.routes[0].legs[i]); durations.push(directionsResult.routes[0].legs[i].duration.value); distances.push(directionsResult.routes[0].legs[i].distance.value);
} if (typeof onProgressCallback == 'function') { onProgressCallback(tsp); } okChunkNode = chunkNode; nextChunk(mode);
} else if (directionsStatus == google.maps.DirectionsStatus.OVER_QUERY_LIMIT) { requestLimitWait *= 2; setTimeout(function(){ nextChunk(mode) }, requestLimitWait);
} else { var errorMsg = DIR_STATUS_MSG[directionsStatus]; var doNotContinue = true; alert("Request failed: " + errorMsg); } });
} else { readyTsp(mode); } } function readyTsp(mode) { //alert("readyTsp"); // Get distances and durations into 2-d arrays: distIndex = 0; legs = new Array(); dist = new Array(); dur = new Array(); numActive = 0; for (var i = 0; i < waypoints.length; ++i) { if (wpActive[i]) { legs.push(new Array()); dist.push(new Array()); dur.push(new Array()); addr[numActive] = addresses[i]; numActive++;
} } for (var i = 0; i < numActive; ++i) { legs[i][i] = null; dist[i][i] = 0; dur[i][i] = 0; } for (var i = 0; i < waypoints.length; ++i) { if (wpActive[i]) { getDistTable(i, 0); break;
} } doTsp(mode); } function doTsp(mode) { visited = new Array(); for (var i = 0; i < numActive; ++i) { visited[i] = false; } currPath = new Array(); bestPath = new Array(); nextSet = new Array(); bestTrip = maxTripSentry; visited[0] = true; currPath[0] = 0; cachedDirections = true;
//hanya menggunakan metode ant colony AntColony(mode); prepareSolution();
} // solusi akhir function prepareSolution() { var wpIndices = new Array(); for (var i = 0; i < waypoints.length; ++i) { if (wpActive[i]) { wpIndices.push(i); } } var bestPathLatLngStr = ""; var directionsResultLegs = new Array(); var directionsResultRoutes = new Array(); var directionsResultOverview = new Array(); var directionsResultBounds = new google.maps.LatLngBounds(); for (var i = 1; i < bestPath.length; ++i) { directionsResultLegs.push(legs[bestPath[i-1]][bestPath[i]]); } for (var i = 0; i < bestPath.length; ++i) { bestPathLatLngStr
- = makeLatLng(waypoints[wpIndices[bestPath[i]]]) + "\n"; directionsResultBounds.extend(waypoints[wpIndices[bestPath[i]]]); directionsResultOverview.push(waypoints[wpIndices[bestPath[i]]]); } directionsResultRoutes.push({ legs: directionsResultLegs, bounds: directionsResultBounds, copyrights: "Map data ©2013 Google", overview_path: directionsResultOverview, warnings: new Array(), }); gebDirectionsResult = fakeDirResult; gebDirectionsResult.routes = directionsResultRoutes; if (onFatalErrorListener) google.maps.event.removeListener(onFatalErrorListener); onFatalErrorListener
= google.maps.event.addListener(gebDirectionsService, 'error', onFatalErrorCallback); if (typeof onSolveCallback == 'function') { onSolveCallback(tsp); } } function reverseSolution() { for (var i = 0; i < bestPath.length / 2; ++i) { var tmp = bestPath[bestPath.length-1-i]; bestPath[bestPath.length-1-i] = bestPath[i]; bestPath[i] = tmp; } prepareSolution(); } function reorderSolution(newOrder) { var newBestPath = new Array(bestPath.length); for (var i = 0; i < bestPath.length; ++i) { newBestPath[i] = bestPath[newOrder[i]]; } bestPath = newBestPath; prepareSolution(); } function removeStop(number) { var newBestPath = new Array(bestPath.length - 1); for (var i = 0; i < bestPath.length; ++i) { if (i != number) { newBestPath[i - (i > number ? 1 : 0)] = bestPath[i]; } } bestPath = newBestPath; prepareSolution(); } function addWaypoint(latLng, label) { var freeInd = -1; for (var i = 0; i < waypoints.length; ++i) { if (!wpActive[i]) { freeInd = i; break;
} } if (freeInd == -1) { if (waypoints.length < maxTspSize) { waypoints.push(latLng); labels.push(label); wpActive.push(true); freeInd = waypoints.length-1;
} else { return(-1); } } else { waypoints[freeInd] = latLng; labels[freeInd] = label; wpActive[freeInd] = true; } return(freeInd); } function addAddress(address, label, callback) { addressProcessing = true; gebGeocoder.geocode({ address: address }, function(results, status) { if (status == google.maps.GeocoderStatus.OK) { addressProcessing = false;
- addressRequests;
- currQueueNum; if (results.length >= 1) { var latLng = results[0].geometry.location;
}, 100); } else {
- addressRequests; alert("Failed to geocode address: " + address + ". Reason: "
- GEO_STATUS_MSG[status]);
- currQueueNum; addressProcessing = false; if (typeof(callback) == 'function') callback(address); }
}); } function swapWaypoints(i, j) { var tmpAddr = addresses[j]; var tmpWaypoint = waypoints[j]; var tmpActive = wpActive[j]; var tmpLabel = labels[j]; addresses[j] = addresses[i]; addresses[i] = tmpAddr; waypoints[j] = waypoints[i]; waypoints[i] = tmpWaypoint; wpActive[j] = wpActive[i]; wpActive[i] = tmpActive; labels[j] = labels[i]; labels[i] = tmpLabel; } BpTspSolver.prototype.startOver = function() { waypoints = new Array(); addresses = new Array(); labels = new Array(); addr = new Array(); wpActive = new Array(); wayArr = new Array(); legsTmp = new Array(); distances = new Array(); durations = new Array(); legs = new Array(); dist = new Array(); dur = new Array(); visited = new Array(); currPath = new Array(); bestPath = new Array(); bestTrip = new Array(); nextSet = new Array(); travelMode = google.maps.DirectionsTravelMode.DRIVING; numActive = 0; chunkNode = 0; okChunkNode = 0; addressRequests = 0; addressProcessing = false; requestNum = 0; currQueueNum = 0; cachedDirections = false; onSolveCallback = function(){}; onProgressCallback = null; doNotContinue = false; directionunits = google.maps.UnitSystem.METRIC; GEO_STATUS_MSG[google.maps.GeocoderStatus.OK] = "Success."; GEO_STATUS_MSG[google.maps.GeocoderStatus.INVALID_REQUEST] = "Request was invalid."; GEO_STATUS_MSG[google.maps.GeocoderStatus.ERROR] = "There was a problem contacting the Google servers."; GEO_STATUS_MSG[google.maps.GeocoderStatus.OVER_QUERY_LIMIT] = "The webpage has gone over the requests limit in too short a period of time."; GEO_STATUS_MSG[google.maps.GeocoderStatus.REQUEST_DENIED] = "The webpage is not allowed to use the geocoder."; GEO_STATUS_MSG[google.maps.GeocoderStatus.UNKNOWN_ERROR] = "A geocoding request could not be processed due to a server error. The request may succeed if you try again."; GEO_STATUS_MSG[google.maps.GeocoderStatus.ZERO_RESULTS] = "No result was found for this GeocoderRequest."; DIR_STATUS_MSG[google.maps.DirectionsStatus.INVALID_REQUEST] = "The DirectionsRequest provided was invalid."; DIR_STATUS_MSG[google.maps.DirectionsStatus.MAX_WAYPOINTS_EXCEEDED] = "Too many DirectionsWaypoints were provided in the DirectionsRequest. The total allowed waypoints is 8, plus the origin and destination."; DIR_STATUS_MSG[google.maps.DirectionsStatus.NOT_FOUND] = "At least one of the origin, destination, or waypoints could not be geocoded."; DIR_STATUS_MSG[google.maps.DirectionsStatus.OK] = "The response contains a valid DirectionsResult."; DIR_STATUS_MSG[google.maps.DirectionsStatus.OVER_QUERY_LIMIT] = "The webpage has gone over the requests limit in too short a period of time."; DIR_STATUS_MSG[google.maps.DirectionsStatus.REQUEST_DENIED] = "The webpage is not allowed to use the directions service."; DIR_STATUS_MSG[google.maps.DirectionsStatus.UNKNOWN_ERROR] = "A directions request could not be processed due to a server error. The request may succeed if you try again."; DIR_STATUS_MSG[google.maps.DirectionsStatus.ZERO_RESULTS] = "No route could be found between the origin and destination."; } /* end (edited) OptiMap code */ /* start public interface */ function BpTspSolver(map, panel, onFatalError) { if (tsp) { alert('You can only create one BpTspSolver at a time.'); return; } gebMap = map; directionsPanel = panel; gebGeocoder = new google.maps.Geocoder(); gebDirectionsService = new google.maps.DirectionsService();
onFatalErrorCallback = onFatalError; // only for fatal errors, not geocoding errors tsp = this; } BpTspSolver.prototype.addAddressWithLabel = function(address, label, callback) {