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 asymptoteFactor = 0.9; // Ketajaman dari reward sebagai solusi mendekati solusi terbaik var pher = new Array(); var nextPher = new Array(); var prob = new Array(); var numAnts = 20; var numWaves = 20; for (var i = 0; i < numActive; ++i) { pher[i] = new Array(); nextPher[i] = new Array(); } for (var i = 0; i < numActive; ++i) { for (var j = 0; j < numActive; ++j) { pher[i][j] = 1; nextPher[i][j] = 0.0;

  } } 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;
    var freeInd = addWaypoint(latLng, label); address = address.replace("'", ""); address = address.replace("\"", ""); addresses[freeInd] = address; if (typeof callback == 'function') callback(address, latLng); } } else if (status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT) { setTimeout(function(){ addAddress(address, label, callback)

  }, 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) {