mirror of
https://github.com/KeymonSoft/Ruteador-NonUI.git
synced 2026-04-17 12:56:10 +00:00
- Cambios en el Algoritmo Genetico.
- Se agregó el HASH al JSON que regresa cuando se genera el ruteo.
This commit is contained in:
21
Files/LICENSE
Normal file
21
Files/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Muyang Ye
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
1033
Files/OSMTools.js
Normal file
1033
Files/OSMTools.js
Normal file
File diff suppressed because it is too large
Load Diff
60
Files/README.md
Normal file
60
Files/README.md
Normal file
@@ -0,0 +1,60 @@
|
||||

|
||||
|
||||
# 🌎 Travelnetics ([demo](https://muyangye.github.io/Traveling_Salesman_Solver_Google_Maps/))
|
||||
The Traveling Salesman Problem statement is as follows:
|
||||
```Given a list of cities and the distances between each pair of cities, what is the shortest possible route that visits each city exactly once and returns to the origin city?```
|
||||
|
||||
This problem is **NP-hard** because it is as hard as a NP-Complete problem Hamilton Cycle and doesn't have an efficient certifier (not necessarily need this to be NP-Hard though). It can not be solved within polynomial time. The reason is this:
|
||||
Suppose there are 19 cities in total, then I have 19 choices of which city should I travel first, 18 choices of which
|
||||
city should I travel second, ..., 1 choice of which city should I travel at last. In total, that is **19!** possibilities,
|
||||
out of the **19!** possibilities, I pick the one that has the shortest total distance.
|
||||
|
||||
If my computer can test **one billion** tours per second. It is going to take **19!/1,000,000,000** seconds ~ **3.85 years**
|
||||
to finish. Therefore, it is unfeasible to enumerate all possibilities. This project proposes a partial solution using
|
||||
`Genetic Algorithm` and calls `Google Maps API` to visualize. You can also utilize this project to plan your travel over 100+ places with ease.
|
||||
|
||||
### You can see a demo [here](https://muyangye.github.io/Traveling_Salesman_Solver_Google_Maps/)
|
||||
(please note that I am using my personal Google Maps API key to host the demo. So I've set up restrictions of daily usage limit.
|
||||
If you see Google Map does not load correctly. It means the daily limit was exceeded. The settings for the demo site are
|
||||
`population` of 128, `numIterations` of 10000, and `mutChance` of 0.2)
|
||||
|
||||
## ▶️ Steps to Run Locally
|
||||
1. Replace `apiKey` attribute in `config.js` with your own Google Maps API Key. If you do not have
|
||||
one, here is the [link](https://developers.google.com/maps/documentation/javascript/get-api-key)
|
||||
to create one (❗❗❗ Note: Fees charged by Google may apply ❗❗❗)
|
||||
2. Open `index.html`, type an address in the search bar and Google Maps' Autocomplete API will
|
||||
show you a list of addresses. click on one will add a waypoint, the **first** waypoint added is the origin
|
||||
3. Check `Return To Origin?` or not, which means whether the solution should include going back to the origin
|
||||
3. Click `Calculate Best Route!` at the bottom of `index.html`, enjoy!
|
||||
|
||||
## ⚙️ Customize Yourself
|
||||
### Edit `config.js`, which contains the following fields:
|
||||
- `popSize`: An `integer` == Population size == The total number of individual routes
|
||||
- `numIterations`: A `number` > `0` == How many iterations the Genetic Algorithm should run. Generally the
|
||||
more iterations, the more GA converges
|
||||
- `mutChance`: A `float` between `0` and `1` == Mutation chance, as explained in `How Does It Work?`
|
||||
|
||||
## 💡 How Does It Work?
|
||||
### [Medium Article](https://medium.com/@realymyplus/introduction-to-genetic-algorithm-with-a-website-to-watch-it-solve-traveling-salesman-problem-live-a21105a3251a)
|
||||
|
||||
## ⚠️Known Defects
|
||||
- This project solely calculates the distance between 2 waypoints using **Haversine distance**.
|
||||
However, this approach has 2 major disadvantages:
|
||||
- **Shortest distance** is not always equal to **shortest time**
|
||||
- **Haversine distance** calculates the distance of a straight line between 2 waypoints,
|
||||
whereas there are other factors involved in the **shortest distance** such as the
|
||||
**existence/straightness of a road** and/or **elevation**
|
||||
- All of the above 2 problems can be solved by simply querying [Google Maps' Directions API](https://developers.google.com/maps/documentation/directions/overview),
|
||||
but again, Google Maps charges very high for this API. In future versions, will add
|
||||
support to let the user decide whether to use [Google Maps' Directions API](https://developers.google.com/maps/documentation/directions/overview)
|
||||
or **Haversine distance** for calculating distances
|
||||
- Genetic Algorithm **does not gurantee** to generate the **global optimal solution** since
|
||||
Genetic Algorithm may converge fairly quickly. This is why we want `mutChance` for mutation
|
||||
to add a little bit of randomness here
|
||||
|
||||
## 🏆Acknowledgments && Disclaimers
|
||||
- This project's idea originates from `ITP 435-Professional C++` taught at the
|
||||
`University of Southern California` designed by [Sanjay Madhav](https://viterbi.usc.edu/directory/faculty/Madhav/Sanjay)
|
||||
- This is the first time I ever touched Javascript. I am a lifelong C++|Python|Java|PHP developer.
|
||||
So please bear with me if my Javascript coding style is a mess. Any suggestions are
|
||||
more than welcome!
|
||||
6
Files/config.js
Normal file
6
Files/config.js
Normal file
@@ -0,0 +1,6 @@
|
||||
config = {
|
||||
"apiKey": "AIzaSyDYUOIGHUNDHrkdsU2B-WT7loUGdqGgCfg", // REPLACE WITH YOUR_API_KEY HERE
|
||||
"popSize": 128,
|
||||
"numIterations": 5000,
|
||||
"mutChance": 0.4,
|
||||
};
|
||||
BIN
Files/cover.png
Normal file
BIN
Files/cover.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 409 KiB |
270
Files/genetic-algorithm.js
Normal file
270
Files/genetic-algorithm.js
Normal file
@@ -0,0 +1,270 @@
|
||||
const CONVERT_TO_RADIAN_CONST = 1; // 0.0174533;
|
||||
|
||||
function loadScript() {
|
||||
var script = document.createElement("script");
|
||||
script.type = "text/javascript";
|
||||
script.src = "https://maps.googleapis.com/maps/api/js?key=" + config["apiKey"] + "&callback=initMap&v=weekly";
|
||||
script.defer = true;
|
||||
document.body.appendChild(script);
|
||||
}
|
||||
|
||||
function initMap() {
|
||||
let waypointsJSON = localStorage.getItem("waypoints");
|
||||
|
||||
// let waypointsJSON = [{"name":"Lago Chalco 47, Anáhuac I Secc, Miguel Hidalgo, 11320 Ciudad de México, CDMX, Mexico","lat":0.33943361448716003,"lon":-1.73094628692019},{"name":"C. Lago Chapala 47, Anáhuac I Secc., Anáhuac I Secc, Miguel Hidalgo, 11320 Ciudad de México, CDMX, Mexico","lat":0.33939502873152005,"lon":-1.73093370832688},{"name":"Lago Texcoco, Anáhuac I Secc, Ciudad de México, CDMX, Mexico","lat":0.33941341578307005,"lon":-1.73099749490239},{"name":"Lago Cuitzeo, Anáhuac I Secc., 11320 Ciudad de México, CDMX, Mexico","lat":0.33936825362399003,"lon":-1.73091535792726}]
|
||||
let returnToOrigin = localStorage.getItem("returnToOrigin");
|
||||
let waypoints = JSON.parse(waypointsJSON);
|
||||
// console.log(">>>>>> ga/waypoints", waypointsJSON);
|
||||
// console.log(waypoints);
|
||||
|
||||
const map = new google.maps.Map(document.getElementById("map"), {
|
||||
center: { lat: waypoints[0].lat / CONVERT_TO_RADIAN_CONST, lng: waypoints[0].lon / CONVERT_TO_RADIAN_CONST},
|
||||
zoom: 8,
|
||||
});
|
||||
|
||||
class Waypoint{
|
||||
constructor(name, location) {
|
||||
this.name = name;
|
||||
this.lat = location.lat();
|
||||
this.lon = location.lng();
|
||||
}
|
||||
}
|
||||
|
||||
var poly = new google.maps.Polyline({
|
||||
editable: true,
|
||||
path: []
|
||||
});
|
||||
|
||||
let popSize = config["popSize"];
|
||||
let numIterations = config["numIterations"];
|
||||
let mutChance = config["mutChance"];
|
||||
|
||||
// Fisher-Yates shuffle algorithm
|
||||
function shuffle(individual) {
|
||||
let i = individual.length;
|
||||
while (--i > 0) {
|
||||
let temp = Math.floor(Math.random() * (i + 1));
|
||||
[individual[temp], individual[i]] = [individual[i], individual[temp]];
|
||||
}
|
||||
}
|
||||
|
||||
// Generate initial population
|
||||
function genInitialPopulation(population) {
|
||||
let individual = []; //Arrego con los puntos a visitar.
|
||||
let zero = [0];
|
||||
for(i=0; i < waypoints.length; ++i){
|
||||
individual.push(i); // Agregamos el primer individuo con el orden original de los puntos.
|
||||
}
|
||||
population.push(individual)
|
||||
for (let i = 0; i < popSize; ++i) { // Agregamos a la poblacion el numero de individuos establecido (popSize).
|
||||
individual = [...Array(waypoints.length - 1).keys()].map(j => ++j); // Quitamos el 0 (punto de origen) porque es el inicio de la ruta, solo barajeamos los demas y luego lo regresamos.
|
||||
shuffle(individual); // Barajeamos los puntos del individuo para tener un individuo random.
|
||||
//console.log(">>>>> ga/individual ", i, [...Array(waypoints.length - 1).keys()].map(j => ++j), individual)
|
||||
population.push(zero.concat(individual)); // Regresamos el 0 (punto de origen) al inicio de la ruta.
|
||||
}
|
||||
// console.log(">>>>> ga/population ", population)
|
||||
}
|
||||
|
||||
// Calculate the Haversine distance between two waypoints
|
||||
function getHaversineDistance(waypoint1, waypoint2) {
|
||||
let dlon = waypoint2.lon - waypoint1.lon;
|
||||
let lat1 = waypoint1.lat;
|
||||
let lat2 = waypoint2.lat;
|
||||
let dlat = lat2 - lat1;
|
||||
let a = Math.pow(Math.sin(dlat/2), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(dlon/2), 2);
|
||||
let c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
|
||||
return 3961 * c;
|
||||
}
|
||||
|
||||
function calcTotalDistance(waypoints, individual) {
|
||||
let totalDistance = 0;
|
||||
for (let i = 0; i < individual.length - 1; ++i) {
|
||||
totalDistance += getDistanceFromLatLonInKm(waypoints[individual[i]], waypoints[individual[i+1]]);
|
||||
}
|
||||
// Add distance back to origin if returnToOrigin is set to true
|
||||
return returnToOrigin === "true" ? totalDistance + getHaversineDistance(waypoints[0], waypoints[individual[individual.length - 1]]) : totalDistance;
|
||||
}
|
||||
|
||||
function getDistanceFromLatLonInKm(waypoint1, waypoint2) {
|
||||
let lat1 = waypoint1.lat;
|
||||
let lon1 = waypoint1.lon;
|
||||
let lat2 = waypoint2.lat;
|
||||
let lon2 = waypoint2.lon;
|
||||
var R = 6371; // Radius of the earth in km
|
||||
var dLat = deg2rad(lat2-lat1); // deg2rad below
|
||||
var dLon = deg2rad(lon2-lon1);
|
||||
var a =
|
||||
Math.sin(dLat/2) * Math.sin(dLat/2) +
|
||||
Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
|
||||
Math.sin(dLon/2) * Math.sin(dLon/2)
|
||||
;
|
||||
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
|
||||
var d = R * c; // Distance in km
|
||||
return d;
|
||||
}
|
||||
|
||||
function deg2rad(deg) {
|
||||
return deg * (Math.PI/180)
|
||||
}
|
||||
|
||||
function normalize(probabilities) {
|
||||
let sum = probabilities.reduce(function(a, b) { //Suma todos los valores del arreglo.
|
||||
return a + b;
|
||||
}, 0);
|
||||
// let x = 0;
|
||||
// probabilities.forEach((probability, index) => {
|
||||
// x += probabilities[index];
|
||||
// });
|
||||
// console.log("##### SUM: ",sum, x);
|
||||
probabilities.forEach((probability, index) => { // Cambia cada valor del arreglo con su valor dividido entre SUM.
|
||||
probabilities[index] /= sum;
|
||||
});
|
||||
}
|
||||
|
||||
function getRandomInclusive() { // Genera un numero ramdom entro 0 y 1, PERO si resulta 0, entonces regresa 1.
|
||||
return Math.random() == 0 ? 1 : Math.random();
|
||||
}
|
||||
|
||||
function getRandomIntInclusive(min, max) {
|
||||
min = Math.ceil(min); // Redondeamos hacia arriba.
|
||||
max = Math.floor(max); // Redondeamos hacia abajo.
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min; // Redondeamos hacia abajo (random * (max - min + 1)).
|
||||
}
|
||||
|
||||
function genNewPopulation(newPopulation, crossoverIndex, individual1, individual2) {
|
||||
let newIndividual = [];
|
||||
++crossoverIndex;
|
||||
for (let i = 0; i < crossoverIndex; ++i) {
|
||||
newIndividual.push(individual1[i]);
|
||||
}
|
||||
for (let i = 0; i < individual2.length; ++i) {
|
||||
if (!newIndividual.includes(individual2[i])) {
|
||||
newIndividual.push(individual2[i]);
|
||||
}
|
||||
}
|
||||
let random = getRandomInclusive();
|
||||
//console.log(random);
|
||||
if (random <= mutChance) {
|
||||
let index1 = getRandomIntInclusive(1, newIndividual.length - 1);
|
||||
let index2 = getRandomIntInclusive(1, newIndividual.length - 1);
|
||||
[newIndividual[index1], newIndividual[index2]] = [newIndividual[index2], newIndividual[index1]];
|
||||
}
|
||||
newPopulation.push(newIndividual);
|
||||
}
|
||||
|
||||
function addToPath(polyPath, latlng, count) {
|
||||
polyPath.push(latlng);
|
||||
if (count != waypoints.length+1) {
|
||||
new google.maps.Marker({
|
||||
position: latlng,
|
||||
label: {text: count.toString(), color: "#00FF00"},
|
||||
animation: google.maps.Animation.DROP,
|
||||
map: map,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function startNewCalculation() {
|
||||
window.location.href = "index.html";
|
||||
}
|
||||
document.getElementById("goto-index").addEventListener("click", startNewCalculation);
|
||||
let waypointsList = document.getElementById("waypoints-list");
|
||||
|
||||
/*
|
||||
INICIAMOS LOS CALCULOS
|
||||
*/
|
||||
let population = [];
|
||||
|
||||
// let fitTemp = [];
|
||||
let sortedIndexTemp = [];
|
||||
genInitialPopulation(population); // Mandamos population en blanco y regresamos 128 (popSize) variaciones.
|
||||
for (let i = 0; i <= numIterations; ++i) {
|
||||
// fitness[i] <==> the ith route's total distance
|
||||
let fitness = [];
|
||||
population.forEach(individual => {
|
||||
fitness.push(calcTotalDistance(waypoints, individual)); // Ponemos en fitness la distancia total entre los puntos de este individuo en particular.
|
||||
});
|
||||
// fitTemp = fitness;
|
||||
// console.log(">>>>> ga/fitness", fitness)
|
||||
let sortedIndexes = [...Array(popSize).keys()].sort((index1, index2) => {
|
||||
return fitness[index1] < fitness[index2] ? -1 : 1;
|
||||
});
|
||||
// console.log(sortedIndexes);
|
||||
|
||||
let probabilities = new Array(popSize).fill(1.0 / popSize); // No se que haga este arreglo de probabilidades, pero se usa en algoritmos geneticos.
|
||||
probabilities[sortedIndexes[0]] *= 6; // Al parecer tiene que ver con las posibiliddes de que un individuo se escoja para la siguiente generación.
|
||||
probabilities[sortedIndexes[1]] *= 6;
|
||||
for (let j = 0; j < popSize / 2; ++j) {
|
||||
probabilities[sortedIndexes[j]] *= 3;
|
||||
}
|
||||
// console.log(">>>>> ga/probabilities", probabilities);
|
||||
// let probs = [] = probabilities;
|
||||
normalize(probabilities);
|
||||
|
||||
// console.log(calcTotalDistance(waypoints, population[sortedIndexes[0]]))
|
||||
|
||||
// console.log(">>>>> ga/probabilities normalizadas", probabilities);
|
||||
if (i == numIterations) { // Si ya completamos el numero de iteraciones especificadas (numIterations), entonces salimos.
|
||||
let solution = population[sortedIndexes[0]];
|
||||
// console.log(">>>>> POPULATION: ", population)
|
||||
console.log(">>>>> FITNESS: ", fitness)
|
||||
// console.log(">>>>> SORTED INDEXES: ", sortedIndexes)
|
||||
// console.log(">>>>> PROBS: ", probs);
|
||||
// console.log(">>>>> PROBABILITIES: ", probabilities)
|
||||
console.log(">>>>> GA/SOLUTION:", solution);
|
||||
console.log(calcTotalDistance(waypoints, solution))
|
||||
let polyPath = [];
|
||||
let count = 0;
|
||||
let waypointElement = null;
|
||||
solution.forEach(waypointIndex => { // Generamos la polilinea para Google Maps.
|
||||
waypoint = waypoints[waypointIndex];
|
||||
waypointElement = document.createElement("li");
|
||||
waypointElement.append(waypoint.name);
|
||||
waypointsList.appendChild(waypointElement);
|
||||
addToPath(polyPath, new google.maps.LatLng(waypoint.lat / CONVERT_TO_RADIAN_CONST, waypoint.lon / CONVERT_TO_RADIAN_CONST), ++count);
|
||||
});
|
||||
if (returnToOrigin === "true") {
|
||||
addToPath(polyPath, new google.maps.LatLng(waypoints[0].lat / CONVERT_TO_RADIAN_CONST, waypoints[0].lon / CONVERT_TO_RADIAN_CONST), ++count);
|
||||
}
|
||||
poly.setPath(polyPath);
|
||||
poly.setMap(map);
|
||||
break;
|
||||
}
|
||||
let index1 = 0;
|
||||
let index2 = 0;
|
||||
let random = 0;
|
||||
let currSum = 0;
|
||||
let crossoverIndex = 0;
|
||||
let aGoesFirst = 0;
|
||||
let newPopulation = [];
|
||||
for (let j = 0; j < popSize; ++j) {
|
||||
currSum = 0;
|
||||
random = getRandomInclusive();
|
||||
for (let k = 0; k < popSize; ++k) { // Generamos index1.
|
||||
currSum += probabilities[k];
|
||||
if (currSum >= random) {
|
||||
index1 = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
currSum = 0;
|
||||
random = getRandomInclusive();
|
||||
for (let k = 0; k < popSize; ++k) { // Generamos index2.
|
||||
currSum += probabilities[k];
|
||||
if (currSum >= random) {
|
||||
index2 = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
crossoverIndex = getRandomIntInclusive(1, waypoints.length - 2);
|
||||
aGoesFirst = getRandomIntInclusive(0, 1);
|
||||
//console.log("****************** ",crossoverIndex, aGoesFirst)
|
||||
// Si aGoesFirst = 0 o 1, entonces obtenemos nueva poblacion de una u otra forma!
|
||||
aGoesFirst ? genNewPopulation(newPopulation, crossoverIndex, population[index1], population[index2])
|
||||
: genNewPopulation(newPopulation, crossoverIndex, population[index2], population[index1]);
|
||||
}
|
||||
population = newPopulation;
|
||||
}
|
||||
//console.log(">>>>> FITNESS TEMP: ", fitTemp)
|
||||
//console.log(">>>>> SORTED INDEXES TEMP: ", sortedIndexTemp)
|
||||
}
|
||||
51
Files/index.html
Normal file
51
Files/index.html
Normal file
@@ -0,0 +1,51 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Travelnetics</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="./style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="pac-card" id="pac-card">
|
||||
<div>
|
||||
<div id="title">Search for Waypoints</div>
|
||||
<br />
|
||||
</div>
|
||||
<div id="pac-container">
|
||||
<input id="pac-input" type="text" placeholder="Enter a location" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="map"></div>
|
||||
|
||||
<!-- Searched data -->
|
||||
<ul id="waypoints-list">
|
||||
</ul>
|
||||
<div id="infowindow-content">
|
||||
<span id="place-name" class="title"></span><br />
|
||||
<span id="place-address"></span>
|
||||
</div>
|
||||
|
||||
<div id="return-to-origin-div">
|
||||
<label>Return to Origin?
|
||||
<input id="return-to-origin" type="checkbox" checked>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div id="button-div">
|
||||
<button id="goto-result">Calculate Best Route!</button>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
The `defer` attribute causes the callback to execute after the full HTML
|
||||
document has been parsed. For non-blocking uses, avoiding race conditions,
|
||||
and consistent behavior across browsers, consider loading using Promises
|
||||
with https://www.npmjs.com/package/@googlemaps/js-api-loader.
|
||||
-->
|
||||
<script src="./config.js"></script>
|
||||
<script src="./map.js"></script>
|
||||
<script defer>
|
||||
window.initMap = initMap;
|
||||
window.onload = loadScript;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
140
Files/map.js
Normal file
140
Files/map.js
Normal file
File diff suppressed because one or more lines are too long
9
Files/osm.html
Normal file
9
Files/osm.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<script type="text/javascript" src="OSMTools.js"></script>
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
at.quelltextlich.osm.embedMapMarkedLocation( 47.07655, 15.43683, 11, 500, 300 );
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
test
|
||||
</body>
|
||||
24
Files/r2.html
Normal file
24
Files/r2.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Travelnetics</title>
|
||||
<link rel="stylesheet" type="text/css" href="./style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
<h2 style="text-align: center;">Results:</h2>
|
||||
<ol style="text-align: center; list-style-position: inside;" id="waypoints-list">
|
||||
</ol>
|
||||
|
||||
<div id="button-div">
|
||||
<button id="goto-index" style="cursor: pointer;">Start a New Calculation!</button>
|
||||
</div>
|
||||
|
||||
<script src="./config.js"></script>
|
||||
<script src="./genetic-algorithm.js"></script>
|
||||
|
||||
<script defer>
|
||||
window.onload = loadScript;
|
||||
window.initMap = initMap;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
24
Files/result.html
Normal file
24
Files/result.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Travelnetics</title>
|
||||
<link rel="stylesheet" type="text/css" href="./style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
<h2 style="text-align: center;">Results:</h2>
|
||||
<ol style="text-align: center; list-style-position: inside;" id="waypoints-list">
|
||||
</ol>
|
||||
|
||||
<div id="button-div">
|
||||
<button id="goto-index" style="cursor: pointer;">Start a New Calculation!</button>
|
||||
</div>
|
||||
|
||||
<script src="./config.js"></script>
|
||||
<script src="./genetic-algorithm.js"></script>
|
||||
|
||||
<script defer>
|
||||
window.onload = loadScript;
|
||||
window.initMap = initMap;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
95
Files/style.css
Normal file
95
Files/style.css
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Always set the map height explicitly to define the size of the div element
|
||||
* that contains the map.
|
||||
*/
|
||||
#map {
|
||||
height: 80%;
|
||||
}
|
||||
|
||||
/*
|
||||
* Optional: Makes the sample page fill the window.
|
||||
*/
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#infowindow-content .title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#infowindow-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#map #infowindow-content {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.pac-card {
|
||||
background-color: #fff;
|
||||
border: 0;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 1px 4px -1px rgba(0, 0, 0, 0.3);
|
||||
margin: 10px;
|
||||
padding: 0 0.5em;
|
||||
font: 400 18px Roboto, Arial, sans-serif;
|
||||
overflow: hidden;
|
||||
font-family: Roboto;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#pac-container {
|
||||
padding-bottom: 12px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
#pac-input {
|
||||
background-color: #fff;
|
||||
font-family: Roboto;
|
||||
font-size: 15px;
|
||||
font-weight: 300;
|
||||
margin-left: 12px;
|
||||
padding: 0 11px 0 13px;
|
||||
text-overflow: ellipsis;
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
#pac-input:focus {
|
||||
border-color: #4d90fe;
|
||||
}
|
||||
|
||||
#title {
|
||||
color: #fff;
|
||||
background-color: #4d90fe;
|
||||
font-size: 25px;
|
||||
font-weight: 500;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
|
||||
#button-div {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#return-to-origin-div {
|
||||
text-align: center;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
#goto-result {
|
||||
border: 2px solid coral;
|
||||
height: 50px;
|
||||
width: 200px;
|
||||
margin-bottom: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#goto-index {
|
||||
border: 2px solid coral;
|
||||
height: 50px;
|
||||
width: 200px;
|
||||
margin-bottom: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
408
Genetic_Algorithm.bas
Normal file
408
Genetic_Algorithm.bas
Normal file
@@ -0,0 +1,408 @@
|
||||
B4J=true
|
||||
Group=Default Group
|
||||
ModulesStructureVersion=1
|
||||
Type=Class
|
||||
Version=10
|
||||
@EndOfDesignText@
|
||||
Sub Class_Globals
|
||||
Dim popSize As Int = 128
|
||||
Dim numIterations As Int = 100
|
||||
Dim mutChance As Double = 0.4
|
||||
Dim population As List
|
||||
Dim bestFitness As List
|
||||
Dim probabilities As List
|
||||
Dim laSolucion, laSolucion2 As individuoT
|
||||
Dim waypoints As List
|
||||
Type individuoT (indice As Int, individuo As List, fitness As Double) ', probabilities As Double
|
||||
Dim listaIndFit As List
|
||||
Dim inicioCont As Double = 0
|
||||
Dim final As String = ""
|
||||
End Sub
|
||||
|
||||
'Initializes the object. You can add parameters to this method if needed.
|
||||
Public Sub Initialize
|
||||
' waypoints = jsonP.
|
||||
End Sub
|
||||
|
||||
'Resumable Subs (wait for / sleep) in server handlers
|
||||
'Resumable subs can only work when there is a message queue.
|
||||
'By default, server handlers end when the Handle sub is completed. They do not create a message loop.
|
||||
'If you want to wait for an event then you need to call StartMessageLoop and later StopMessageLoop.
|
||||
'https://www.b4x.com/android/forum/threads/resumable-subs-wait-for-sleep-in-server-handlers.81833/
|
||||
Sub Handle(req As ServletRequest, resp As ServletResponse)
|
||||
Log("##############################################################")
|
||||
Log("############# GA/Handle ########################")
|
||||
Log("##############################################################")
|
||||
Private coords As String = req.GetParameter("c")
|
||||
final = req.GetParameter("f")
|
||||
If coords <> "" Then
|
||||
Private latF As String = "0"
|
||||
Private lonF As String = "0"
|
||||
If final <> "" Then ' Coordenadas del punto final.
|
||||
Private tmpF() As String = Regex.Split(",", final)
|
||||
latF = tmpF(2)
|
||||
lonF = tmpF(1)
|
||||
End If
|
||||
waypoints.Initialize
|
||||
Private coords2() As String = Regex.Split(";", coords)
|
||||
For i = 0 To coords2.Length - 1
|
||||
Private tmpS() As String = Regex.Split(",", coords2(i))
|
||||
If (latF <> tmpS(2) And lonF <> tmpS(1)) Or i = 0 Then ' Quitamos las coordenadas del punto final de los waypoints para agregarlas despues
|
||||
waypoints.Add(CreateMap("id":tmpS(0), "lon":tmpS(1), "lat":tmpS(2)))
|
||||
End If
|
||||
Next
|
||||
If final <> "" Then
|
||||
waypoints.Add(CreateMap("id":tmpF(0), "lon":lonF, "lat":latF))
|
||||
End If
|
||||
End If
|
||||
Log(waypoints)
|
||||
resp.ContentType = "text/html"
|
||||
' Dim l0 As List
|
||||
' l0.Initialize2(Array As Int(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20))
|
||||
' resp.Write($"${l0}<br>"$)
|
||||
' Log(l0)
|
||||
' For i = 0 To 10
|
||||
' resp.Write($"${ShuffleList(l0)}<br>"$)
|
||||
'' Log(ShuffleList(l0))
|
||||
' Next
|
||||
|
||||
' Log($"${l0}${CRLF}${l1}"$)
|
||||
population.Initialize
|
||||
bestFitness.Initialize
|
||||
laSolucion.Initialize
|
||||
laSolucion2.Initialize
|
||||
population = GenInitialPopulation(population)
|
||||
inicioCont = DateTime.now
|
||||
For h = 0 To numIterations
|
||||
' Log("#########################################################################################")
|
||||
' Log("############################## NUEVA POBLACION ###################################")
|
||||
' Log("#########################################################################################")
|
||||
' Log(population)
|
||||
Private fitness As List
|
||||
listaIndFit.Initialize
|
||||
fitness.Initialize
|
||||
probabilities.Initialize
|
||||
For j = 0 To population.Size - 1
|
||||
' Log(j)
|
||||
Private thisFitness As Double = calculateTotalDistance(waypoints, population.get(j))
|
||||
fitness.Add(thisFitness)
|
||||
Private indFit As individuoT
|
||||
indFit.indice = j
|
||||
indFit.individuo = population.get(j)
|
||||
indFit.fitness = thisFitness
|
||||
probabilities.Add(1.0 / popSize) 'indFit.
|
||||
listaIndFit.Add(indFit) 'Ponemos en listaIndFit, el Indice de la poblacion, el individuo y el fitness
|
||||
Next
|
||||
|
||||
fitness.Sort(True)
|
||||
' Log(fitness)
|
||||
listaIndFit.SortType("fitness", True) ' Ordenamos la lista por fitness.
|
||||
' Log("BEST FITNESS" & listaIndFit.Get(0))
|
||||
bestFitness.Add(listaIndFit.Get(0)) ' Agregamos la mejor a bestFitness.
|
||||
' Log("***** listaIndFit: " & listaIndFit)
|
||||
' Log(listaIndFit.Size)
|
||||
|
||||
' Modificamos las probabilidades de selección de individuos en la población.
|
||||
Private tmpIndFit As individuoT
|
||||
tmpIndFit = listaIndFit.Get(0)
|
||||
probabilities.Set(0, probabilities.Get(0) * 6)
|
||||
listaIndFit.Set(0, tmpIndFit)
|
||||
tmpIndFit = listaIndFit.Get(1)
|
||||
probabilities.set(1, probabilities.Get(1) * 6)
|
||||
listaIndFit.Set(1, tmpIndFit)
|
||||
For i = 0 To (popSize / 2) - 1
|
||||
tmpIndFit = listaIndFit.Get(i)
|
||||
probabilities.set(i, probabilities.Get(i) * 3)
|
||||
listaIndFit.Set(i, tmpIndFit)
|
||||
Next
|
||||
|
||||
' Normalizamos las probabilidades de selección de individuos
|
||||
Private sum As Double = 0
|
||||
For i = 0 To popSize - 1
|
||||
sum = sum + probabilities.Get(i)
|
||||
Next
|
||||
For i = 0 To popSize - 1
|
||||
tmpIndFit = listaIndFit.Get(i)
|
||||
probabilities.set(i, probabilities.Get(i) / sum)
|
||||
listaIndFit.Set(i, tmpIndFit)
|
||||
Next
|
||||
|
||||
If h = numIterations Then
|
||||
bestFitness.SortType("fitness", True)
|
||||
laSolucion = bestFitness.Get(0)
|
||||
Log("#################################################################################")
|
||||
Log($"################ LA SOLUCION ES: ${CRLF}${laSolucion}"$)
|
||||
Log("#################################################################################")
|
||||
resp.Write($"<b># LA SOLUCION ES:</b><br>${CRLF}${laSolucion}<br>"$)
|
||||
resp.Write($"<b># PUNTOS:</b> ${laSolucion.individuo.Size}<br>"$)
|
||||
DateTime.DateFormat="yyMMddHHmmss"
|
||||
Log("TIEMPO : " & ((DateTime.Now-inicioCont)/1000))
|
||||
|
||||
Private coords4 As String = ""
|
||||
Private laDist As Double = 0
|
||||
Private lonAnt, latAnt As Double
|
||||
For v = 0 To laSolucion.individuo.Size - 1
|
||||
' Log( $"${laSolucion.individuo.Get(v)} - ${waypoints.Get(laSolucion.individuo.Get(v))}"$ )
|
||||
Private lasCoords As Map = waypoints.Get(v)
|
||||
If coords4 = "" Then ' Generamos coordenadas para ver el mapa en osm.quelltextlich.at/
|
||||
coords4 = $"${lasCoords.get("lon")},${lasCoords.get("lat")}"$
|
||||
Else
|
||||
coords4 = $"${coords4}:${lasCoords.get("lon")},${lasCoords.get("lat")}"$
|
||||
End If
|
||||
If v > 0 Then
|
||||
Private lasCoordsAnt As Map = waypoints.Get((v - 1))
|
||||
laDist = laDist + Main.calculateDistance1(lasCoordsAnt.Get("lat"), lasCoordsAnt.Get("lon"),lasCoords.Get("lat"), lasCoords.Get("lon"))
|
||||
End If
|
||||
lonAnt = lasCoords.get("lon")
|
||||
latAnt = lasCoords.get("lat")
|
||||
Next
|
||||
If final <> "" Then
|
||||
' Log($"${waypoints.Get(waypoints.Size-2).As(Map).Get("id")},${waypoints.Get(waypoints.Size-2).As(Map).Get("lat")}, ${waypoints.Get(waypoints.Size-2).As(Map).Get("lon")}, ${latF}, ${lonF}"$)
|
||||
' Log(laDist)
|
||||
laDist = laDist + calculateDistance1(waypoints.Get(waypoints.Size-2).As(Map).Get("lat"), waypoints.Get(waypoints.Size-2).As(Map).Get("lon"), latF, lonF)
|
||||
' Log(laDist)
|
||||
End If
|
||||
Log("DISTANCIA ORIGINAL: " & laDist)
|
||||
resp.Write($"<b># DISTANCIA ORIGINAL: </b>${NumberFormat2(laDist, 1, 2, 2, True)}<br>"$)
|
||||
|
||||
Private coords4 As String = ""
|
||||
Private laDist As Double = 0
|
||||
Private lonAnt, latAnt As Double
|
||||
For v = 0 To laSolucion.individuo.Size - 1
|
||||
' Log( $"${laSolucion.individuo.Get(v)} - ${waypoints.Get(laSolucion.individuo.Get(v))}"$ )
|
||||
Private lasCoords As Map = waypoints.Get(laSolucion.individuo.Get(v))
|
||||
If coords4 = "" Then ' Generamos coordenadas para ver el mapa en osm.quelltextlich.at/
|
||||
coords4 = $"${lasCoords.get("lon")},${lasCoords.get("lat")}"$
|
||||
Else
|
||||
coords4 = $"${coords4}:${lasCoords.get("lon")},${lasCoords.get("lat")}"$
|
||||
End If
|
||||
If v > 0 Then
|
||||
Private lasCoordsAnt As Map = waypoints.Get(laSolucion.individuo.Get(v - 1))
|
||||
' Log($"${laSolucion.individuo.Get(v - 1)} -> ${laSolucion.individuo.Get(v)} = ${numberformat2(laDist, 1, 2, 2, True)} + ${Main.calculateDistance1(lasCoordsAnt.Get("lat"), lasCoordsAnt.Get("lon"),lasCoords.Get("lat"), lasCoords.Get("lon"))} = ${numberformat2(ladist + Main.calculateDistance1(lasCoordsAnt.Get("lat"), lasCoordsAnt.Get("lon"),lasCoords.Get("lat"), lasCoords.Get("lon")),1,2,2,True)}"$)
|
||||
laDist = laDist + Main.calculateDistance1(lasCoordsAnt.Get("lat"), lasCoordsAnt.Get("lon"),lasCoords.Get("lat"), lasCoords.Get("lon"))
|
||||
End If
|
||||
lonAnt = lasCoords.get("lon")
|
||||
latAnt = lasCoords.get("lat")
|
||||
Next
|
||||
Log("DISTANCIA MEJORADA: " & laDist)
|
||||
resp.Write($"<b># DISTANCIA MEJORADA: </b>${NumberFormat2(laDist, 1, 2, 2, True)}"$)
|
||||
|
||||
|
||||
' Private laDistOrig As Double = 0
|
||||
' Private origCoords As String = "-98.367397,20.2885251:-98.3673986,20.2842333:-98.4171617,20.2875307:-98.4171617,20.2870722:-98.2018217,20.157312:-98.2037883,20.1579131:-98.2033956,20.1597869:-98.2037471,20.1600194:-98.3304542,20.2411999:-98.3675814,20.157501:-98.3981804,20.1613062:-98.3981877,20.1611756:-98.3981638,20.1611726:-98.3981838,20.1528387:-98.4105988,20.1604658:-98.4105797,20.1604658:-98.4106149,20.1601633:-98.4105995,20.1582812:-98.4171635,20.0934635:-98.3746171,20.0937065:-98.3113997,20.0373747:-98.3097373,20.0378:-98.3097854,20.0378621:-98.3097373,20.03822:-98.3091305,20.0382337:-98.3092364,20.0295646:-98.3020753,20.0281433:-98.2993573,19.9890079:-98.2994654,20.0191821:-98.2997214,20.0191883:-98.2998736,20.0373747:-98.2965265,20.0374267:-98.2974103,20.0382089:-98.2974578,20.0382999:-98.2998506,20.0373507:-98.3001282,20.0374151:-98.3011024,20.0382249:-98.3019379,20.0373344:-98.3024263,20.0382022:-98.3024866,20.0381959:-98.3047418,20.0372789:-98.3048551,20.0373969:-98.3087633,20.0373588:-98.3091585,20.038213:-98.3096702,20.0382294:-98.3098262,20.0382301:-98.3098019,20.0382226:-98.3098507,20.0382032:-98.309962,20.0382169:-98.310657,20.0382241:-98.3545391,20.0765822:-98.3674448,20.0883075:-98.3674109,20.0883744:-98.3717499,20.0904887:-98.3733305,20.0934303:-98.3729919,20.1005734:-98.3674397,20.1069279:-98.3597017,20.1002531:-98.3603581,20.0989735:-98.3578046,20.0983058:-98.3575839,20.0997116:-98.3571027,20.102067:-98.3575733,20.102067:-98.35414,20.106525:-98.3547467,20.1085665:-98.3569592,20.1102607:-98.3543659,20.097339:-98.354654,20.0976982:-98.355117,20.1066587:-98.3568694,20.1071554:-98.3571229,20.106387:-98.3602375,20.1011948:-98.359305,20.1076649:-98.3595572,20.1072504:-98.3600443,20.1044867:-98.360066,20.1044785:-98.367437,20.0989306:-98.3683624,20.097075:-98.3717737,20.0960621:-98.3732723,20.0958825:-98.3739688,20.0950052:-98.3744864,20.0959816:-98.3748629,20.0952055:-98.4171079,20.0942:-98.4171454,20.0950241:-98.4171373,20.0951271:-98.4171682,20.0969286:-98.4782102,20.0689478:-98.4821405,20.0794694:-98.5321791,20.0950872:-98.5316393,20.0950869:-98.5316151,20.0950928:-98.5313826,20.0950772:-98.5311545,20.0950977:-98.5311341,20.0950882:-98.5307409,20.0950772:-98.5310337,20.0880191:-98.5117017,20.0950945:-98.4964301,20.095097:-98.4954019,20.0950948:-98.4797164,20.0950921:-98.4793191,20.0950853:-98.4773212,20.0950898:-98.4731448,20.0950862:-98.4171953,20.0969398:-98.4171583,20.1079494:-98.4158139,20.1541421:-98.4185455,20.1598054:-98.4175739,20.1604813:-98.4171777,20.1600988:-98.4171707,20.1586434:-98.410603,20.1551811:-98.4018328,20.1582555:-98.4017017,20.1586705:-98.4015936,20.1598066:-98.3986541,20.1600943:-98.3981603,20.1599041:-98.3675814,20.1600466:-98.3674102,20.160304:-98.3674328,20.2380154:-98.3674147,20.2631807:-98.3580592,20.2664201:-98.348528,20.2820715:-98.3472617,20.2878516:-98.3470749,20.2869986:-98.3473113,20.285622:-98.3485247,20.2856734:-98.3485252,20.2840998:-98.3673448,20.2845417:-98.3674329,20.2875573:-98.3674382,20.287592:-98.3674382,20.2879142"
|
||||
'' Private origCoords As String = "ESE05002,-98.367397,20.2885251;ESE05003,-98.3674382,20.287592;ESE05004,-98.3674382,20.2879142;ESE05005,-98.3304542,20.2411999;ESE05006,-98.3674147,20.2631807;ESE05007,-98.348528,20.2820715;ESE05008,-98.3981838,20.1528387;ESE05009,-98.4158139,20.1541421;ESE05010,-98.410603,20.1551811;ESE05011,-98.4105995,20.1582812;ESE05012,-98.3674102,20.160304;ESE05013,-98.2018217,20.157312;ESE05014,-98.3986541,20.1600943;ESE05015,-98.3717737,20.0960621;ESE05016,-98.3733305,20.0934303;ESE05017,-98.354654,20.0976982;ESE05018,-98.3543659,20.097339;ESE05019,-98.3578046,20.0983058;ESE05020,-98.3597017,20.1002531;ESE05021,-98.359305,20.1076649;ESE05022,-98.367437,20.0989306;TSE0555000,-98.3683624,20.097075;115683,-98.3744864,20.0959816;115685,-98.3746171,20.0937065;115686,-98.3717499,20.0904887;115687,-98.4171454,20.0950241;115688,-98.4171373,20.0951271;115690,-98.4171953,20.0969398;115693,-98.3729919,20.1005734;115694,-98.3732723,20.0958825;115695,-98.4171635,20.0934635;115696,-98.4171583,20.1079494;115697,-98.35414,20.106525;115699,-98.355117,20.1066587;115701,-98.3575839,20.0997116;115702,-98.3575733,20.102067;115703,-98.3603581,20.0989735;115707,-98.3600443,20.1044867;115712,-98.3571027,20.102067;115713,-98.3602375,20.1011948;115714,-98.360066,20.1044785;115715,-98.3674397,20.1069279;115717,-98.3595572,20.1072504;115718,-98.3568694,20.1071554;115720,-98.3470749,20.2869986;115721,-98.3580592,20.2664201;115722,-98.3674329,20.2875573;115723,-98.4171617,20.2870722;115725,-98.3473113,20.285622;115726,-98.3485247,20.2856734;115728,-98.4171617,20.2875307;115734,-98.3673448,20.2845417;115740,-98.5307409,20.0950772;115741,-98.5313826,20.0950772;115742,-98.5311545,20.0950977;115743,-98.3092364,20.0295646;115744,-98.2993573,19.9890079;115745,-98.3001282,20.0374151;115746,-98.2998736,20.0373747;115747,-98.3113997,20.0373747;115748,-98.3048551,20.0373969;115749,-98.3981877,20.1611756;115750,-98.3981638,20.1611726;115751,-98.2033956,20.1597869;115752,-98.3981603,20.1599041;115753,-98.3675814,20.1600466;115754,-98.3981804,20.1613062;115755,-98.3675814,20.157501;115756,-98.2037883,20.1579131;115757,-98.4018328,20.1582555;115760,-98.4017017,20.1586705;115761,-98.2037471,20.1600194;115764,-98.5316151,20.0950928;115765,-98.4731448,20.0950862;115767,-98.4793191,20.0950853;115768,-98.4185455,20.1598054;115769,-98.4773212,20.0950898;115770,-98.4782102,20.0689478;115771,-98.5117017,20.0950945;115772,-98.5321791,20.0950872;115773,-98.5310337,20.0880191;115774,-98.4797164,20.0950921;115775,-98.4954019,20.0950948;115776,-98.4964301,20.095097;115778,-98.2974103,20.0382089;115779,-98.2974578,20.0382999;115780,-98.2997214,20.0191883;115781,-98.2965265,20.0374267;115782,-98.3096702,20.0382294;115783,-98.3020753,20.0281433;115784,-98.3097373,20.0378;115786,-98.3097373,20.03822;115787,-98.3024263,20.0382022;115788,-98.3024866,20.0381959;115789,-98.2998506,20.0373507;115792,-98.3098507,20.0382032;115793,-98.3019379,20.0373344;115794,-98.3098262,20.0382301;115795,-98.2994654,20.0191821;115797,-98.4171682,20.0969286;115799,-98.3748629,20.0952055;115803,-98.3739688,20.0950052;115843,-98.3087633,20.0373588;115844,-98.3098019,20.0382226;115845,-98.309962,20.0382169;115847,-98.3097854,20.0378621;115849,-98.3547467,20.1085665;115850,-98.3571229,20.106387;115851,-98.3569592,20.1102607;115852,-98.3011024,20.0382249;115853,-98.3545391,20.0765822;115854,-98.310657,20.0382241;115860,-98.4175739,20.1604813;115864,-98.5311341,20.0950882;357004,-98.3472617,20.2878516;357005,-98.3485252,20.2840998;357006,-98.3674328,20.2380154;357007,-98.3673986,20.2842333;357089,-98.4105797,20.1604658;357090,-98.4106149,20.1601633;357091,-98.4105988,20.1604658;357092,-98.4015936,20.1598066;357093,-98.4171777,20.1600988;357094,-98.4171707,20.1586434;357195,-98.5316393,20.0950869;357196,-98.4821405,20.0794694;357305,-98.3091585,20.038213;357306,-98.3091305,20.0382337;357307,-98.3674109,20.0883744;357308,-98.3674448,20.0883075;357309,-98.3047418,20.0372789;357651,-98.4171079,20.0942"
|
||||
'
|
||||
' Private oc() As String = Regex.Split(":", origCoords)
|
||||
' For w = 0 To oc.Length - 1
|
||||
' Private lascoords2() As String = Regex.Split(",", oc(w))
|
||||
' Private lat2 As Double = lascoords2(1)
|
||||
' Private lon2 As Double = lascoords2(0)
|
||||
' If w > 0 Then
|
||||
' Private lascoordsAnt2() As String = Regex.Split(",", oc(w - 1))
|
||||
' Private latAnt2 As Double = lascoordsAnt2(1)
|
||||
' Private lonAnt2 As Double = lascoordsAnt2(0)
|
||||
' laDistOrig = laDistOrig + Main.calculateDistance1(latAnt2, lonAnt2, lat2, lon2)
|
||||
' End If
|
||||
' Next
|
||||
' Log("laDistOrig: " & laDistOrig)
|
||||
|
||||
|
||||
Log("Liga para ver la ruta en mapa:" & CRLF)
|
||||
Log($"https://osm.quelltextlich.at/viewer-js.html?kml_url=http://keymon.lat:9001/kmz.php?c=${coords4}"$)
|
||||
resp.Write($"<br><b># FITNESS :</b> ${CRLF}${NumberFormat2(laSolucion.fitness, 1, 2, 2, True)}"$)
|
||||
resp.Write($"<br><b># TIEMPO :</b> ${CRLF}${(DateTime.Now-inicioCont)/1000}"$)
|
||||
End If
|
||||
|
||||
Private index1 As Int = 0
|
||||
Private index2 As Int = 0
|
||||
Private random As Double = 0
|
||||
Private currSum As Double = 0
|
||||
Private crossoverIndex As Int = 0
|
||||
Private aGoesFirst As Int = 0
|
||||
Private newPopulation As List
|
||||
newPopulation.Initialize
|
||||
' newPopulation.Add(listaIndFit.Get(0))
|
||||
' Log(listaIndFit.Size)
|
||||
For k = 0 To popSize - 1
|
||||
currSum = 0
|
||||
random = getRandomInclusive
|
||||
For m = 0 To popSize - 1
|
||||
currSum = currSum + probabilities.Get(m)
|
||||
' Log(listaIndFit.Get(m).As(individuoT).probabilities)
|
||||
' Log($">>>>>> currSum: ${currSum}, random: ${random}"$)
|
||||
If currSum >= random Then
|
||||
index1 = m
|
||||
Exit
|
||||
End If
|
||||
Next
|
||||
currSum = 0
|
||||
random = getRandomInclusive
|
||||
For m = 0 To popSize - 1
|
||||
currSum = currSum + probabilities.Get(m)
|
||||
currSum = currSum + probabilities.Get(listaIndFit.Get(m).As(individuoT).indice)
|
||||
' Log(listaIndFit.Get(m).As(individuoT).probabilities)
|
||||
' Log($">>>>>> currSum: ${currSum}, random: ${random}"$)
|
||||
If currSum >= random Then
|
||||
index2 = m
|
||||
Exit
|
||||
End If
|
||||
Next
|
||||
crossoverIndex = getRandomIntInclusive(1, waypoints.Size - 2)
|
||||
aGoesFirst = getRandomIntInclusive(0, 1)
|
||||
' Log($"Index1: ${index1}, Index2: ${index2}, CrossoverIndex: ${crossoverIndex}, aGoesFirst: ${aGoesFirst}, WPS: ${waypoints.Size - 2}"$)
|
||||
If aGoesFirst = 0 Then
|
||||
newPopulation = genNewPopulation(newPopulation, crossoverIndex, population.Get(index1), population.Get(index2))
|
||||
Else
|
||||
newPopulation = genNewPopulation(newPopulation, crossoverIndex, population.Get(index2), population.Get(index1))
|
||||
End If
|
||||
If k = 0 Then
|
||||
newPopulation.Add(listaIndFit.Get(0).As(individuoT).individuo)
|
||||
' Log("+++++ " & listaIndFit.Get(0))
|
||||
End If
|
||||
Next
|
||||
|
||||
|
||||
population = newPopulation
|
||||
' Log("POPULATION: " & CRLF & population.Get(0))
|
||||
|
||||
' Log(listaIndFit)
|
||||
' Log(listaIndFit.Size)
|
||||
Next
|
||||
End Sub
|
||||
|
||||
Sub GenInitialPopulation(population0 As List) As List
|
||||
Dim individual As List
|
||||
Dim primero, tempInd As List
|
||||
Private pFinal As Int
|
||||
Dim shuffled As List
|
||||
Private nuevoIndividuo As List
|
||||
individual.Initialize
|
||||
primero.Initialize
|
||||
tempInd.Initialize
|
||||
shuffled.Initialize
|
||||
For i = 0 To waypoints.size - 1 ' Generamos un individuo con el orden original de la ruta (0,1,2,3,4,5... etc)
|
||||
individual.Add(i)
|
||||
Next
|
||||
primero.AddAll(individual)
|
||||
tempInd.AddAll(individual)
|
||||
population0.Add(primero) 'Agregamos el individuo con el orden original al principio de la poblacion.
|
||||
If final <> "" Then pFinal = tempInd.get(tempInd.Size - 1)
|
||||
Log("## " & tempInd)
|
||||
For i = 0 To popSize - 1
|
||||
If final <> "" Then tempInd.RemoveAt(tempInd.Size - 1) ' Quitamos el punto final, porque es el punto final de la ruta.
|
||||
tempInd.RemoveAt(0) ' Quitamos el punto inicial, porque es el punto de inicio
|
||||
' Log(tempInd)
|
||||
' nuevoIndividuo = individual
|
||||
shuffled = ShuffleList(tempInd)
|
||||
' Log(shuffled)
|
||||
shuffled.InsertAt(0, 0)
|
||||
If final <> "" Then shuffled.Add(pFinal) ' Agregamos el punto final al final del individuo.
|
||||
' Log(shuffled)
|
||||
nuevoIndividuo.Initialize
|
||||
nuevoIndividuo.AddAll(shuffled)
|
||||
' Log(nuevoIndividuo)
|
||||
' Log("#")
|
||||
population0.Add(nuevoIndividuo)
|
||||
Next
|
||||
' Log("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
|
||||
' Log($"POPULATION0: ${population0}"$)
|
||||
Return population0
|
||||
End Sub
|
||||
|
||||
Sub ShuffleList(pl As List) As List
|
||||
' Private l As List
|
||||
' l = pl
|
||||
For i = pl.Size - 1 To 0 Step -1
|
||||
Dim j As Int
|
||||
Dim k As Object
|
||||
j = Rnd(0, i + 1)
|
||||
k = pl.Get(j)
|
||||
pl.Set(j,pl.Get(i))
|
||||
pl.Set(i,k)
|
||||
Next
|
||||
Return pl
|
||||
End Sub
|
||||
|
||||
'Calculate distance - Haversine
|
||||
'Using average radius of earth 6378.137 km.
|
||||
Sub calculateDistance1(Latitude1 As Double, Longitude1 As Double, Latitude2 As Double, Longitude2 As Double) As Double 'ignore
|
||||
Return NumberFormat2(2 * 6378137 * ASin (Sqrt (SinD ((Latitude2 - Latitude1) * 0.5) * SinD ((Latitude2 - Latitude1) * 0.5) + CosD (Latitude1) * CosD (Latitude2) * SinD ((Longitude2 - Longitude1) * 0.5) * SinD ((Longitude2 - Longitude1) * 0.5))), 1, 2, 2, False)
|
||||
End Sub
|
||||
|
||||
Sub calculateTotalDistance(waypoints0 As List, individual As List) As String
|
||||
Dim totalDistance As Double = 0
|
||||
' Log("*******************************************************************************")
|
||||
' Log(individual)
|
||||
For i = 0 To individual.Size - 2
|
||||
Private nuevaDist As Double = calculateDistance1(waypoints0.Get(individual.get(i)).As(Map).get("lat"), waypoints0.Get(individual.get(i)).As(Map).get("lon"), waypoints0.Get(individual.get(i+1)).As(Map).get("lat"), waypoints0.Get(individual.get(i+1)).As(Map).get("lon"))
|
||||
' Log(">>>>>>> " & i & "|" & totalDistance & " + " & nuevaDist)
|
||||
totalDistance = totalDistance + nuevaDist
|
||||
' Log($"${waypoints0.Get(individual.get(i))}, ${waypoints0.Get(individual.get(i)).As(Map).get("lon")}, ${waypoints0.Get(individual.get(i)).As(Map).get("lat")}"$)
|
||||
' Log($"${waypoints0.Get(individual.get(i+1))}, ${waypoints0.Get(individual.get(i+1)).As(Map).get("lon")}, ${waypoints0.Get(individual.get(i+1)).As(Map).get("lat")}"$)
|
||||
' Log( totalDistance)
|
||||
Next
|
||||
' Log(totalDistance)
|
||||
Return totalDistance
|
||||
End Sub
|
||||
|
||||
Sub getRandomInclusive As Double
|
||||
Private j As Double
|
||||
j = Rnd(0, 10000000000)
|
||||
j = j / 10000000000
|
||||
' Log(j)
|
||||
If j = 0 Then j = 1
|
||||
' Log(j)
|
||||
Return j
|
||||
End Sub
|
||||
|
||||
Sub getRandomIntInclusive(Min0 As Int, Max0 As Int) As Int
|
||||
Min0 = Ceil(Min0) ' Redondeamos hacia arriba.
|
||||
Max0 = Floor(Max0) ' Redondeamos hacia abajo.
|
||||
Private j As Double
|
||||
j = Rnd(Min0, Max0 + 1)
|
||||
Return j
|
||||
End Sub
|
||||
|
||||
Sub genNewPopulation(newPopulation As List, crossoverIndex As Int, individual1 As List, individual2 As List) As List
|
||||
Private newIndividual As List
|
||||
Private index1, index2 As Int
|
||||
Private random As Double
|
||||
Private lTemp1, lTemp2 As Int
|
||||
newIndividual.Initialize
|
||||
crossoverIndex = crossoverIndex + 1
|
||||
' Log(crossoverIndex + 1)
|
||||
For i = 0 To crossoverIndex - 1
|
||||
newIndividual.Add(individual1.get(i))
|
||||
Next
|
||||
For i = 0 To individual2.Size - 1
|
||||
If newIndividual.IndexOf(individual2.get(i)) = -1 Then
|
||||
newIndividual.Add(individual2.get(i))
|
||||
End If
|
||||
Next
|
||||
' Log(newIndividual)
|
||||
random = getRandomInclusive
|
||||
' Log(random & "|" & mutChance)
|
||||
' Log(newIndividual.size)
|
||||
If random <= mutChance Then
|
||||
index1 = getRandomIntInclusive(1, newIndividual.Size - 1)
|
||||
index2 = getRandomIntInclusive(1, newIndividual.Size - 1)
|
||||
' Log($"${index1}, ${index2}, ${newIndividual.Size}"$)
|
||||
' Log(newIndividual)
|
||||
lTemp1 = newIndividual.Get(index1)
|
||||
lTemp2 = newIndividual.Get(index2)
|
||||
newIndividual.Set(index1, lTemp2)
|
||||
newIndividual.Set(index2, lTemp1)
|
||||
End If
|
||||
newIndividual.RemoveAt(newIndividual.IndexOf(newIndividual.Size - 1))
|
||||
newIndividual.Add(newIndividual.Size)
|
||||
newPopulation.Add(newIndividual)
|
||||
' Log(newIndividual)
|
||||
Return newPopulation
|
||||
End Sub
|
||||
|
||||
Sub traeDistanciaDesdeMatriz(punto1 As Int, punto2 As Int)
|
||||
Private id1 As String = waypoints.Get(punto1).As(Map).Get("id")
|
||||
Private id2 As String = waypoints.Get(punto2).As(Map).Get("id")
|
||||
Private c As ResultSet = Main.db.ExecQuery($"select ${id1} from R113A68_7A7FC9F7_matriz where idT = '${id2}'"$)
|
||||
|
||||
End Sub
|
||||
62
Genetic_Algorythm.bas
Normal file
62
Genetic_Algorythm.bas
Normal file
@@ -0,0 +1,62 @@
|
||||
B4J=true
|
||||
Group=Default Group
|
||||
ModulesStructureVersion=1
|
||||
Type=Class
|
||||
Version=10
|
||||
@EndOfDesignText@
|
||||
Sub Class_Globals
|
||||
Dim population As List
|
||||
Dim sortedIndexTemp As List
|
||||
End Sub
|
||||
|
||||
'Initializes the object. You can add parameters to this method if needed.
|
||||
Public Sub Initialize
|
||||
|
||||
End Sub
|
||||
|
||||
'Resumable Subs (wait for / sleep) in server handlers
|
||||
'Resumable subs can only work when there is a message queue.
|
||||
'By default, server handlers end when the Handle sub is completed. They do not create a message loop.
|
||||
'If you want to wait for an event then you need to call StartMessageLoop and later StopMessageLoop.
|
||||
'https://www.b4x.com/android/forum/threads/resumable-subs-wait-for-sleep-in-server-handlers.81833/
|
||||
Sub Handle(req As ServletRequest, resp As ServletResponse)
|
||||
Log("##############################################################")
|
||||
Log("############# GA/Handle ########################")
|
||||
Log("##############################################################")
|
||||
resp.ContentType = "text/html"
|
||||
Dim l0 As List
|
||||
l0.Initialize2(Array As Int(1,2,3,4,5))
|
||||
resp.Write($"${Shuffle(l0)}"$)
|
||||
|
||||
End Sub
|
||||
|
||||
Sub genInitialPopulation(population1 As List) ' Mandamos population en blanco y regresamos 128 (popSize) variaciones.
|
||||
|
||||
End Sub
|
||||
|
||||
'Generate random string array
|
||||
Sub ShuffleArray(StringArray() As String)
|
||||
Dim ArrayVal As String
|
||||
Dim Random As Int
|
||||
For i = 0 To StringArray.Length - 1
|
||||
Random = Rnd(i, StringArray.Length)
|
||||
ArrayVal = StringArray(i)
|
||||
StringArray(i) = StringArray(Random)
|
||||
StringArray(Random) = ArrayVal
|
||||
Next
|
||||
End Sub
|
||||
|
||||
'Generate random string array
|
||||
Sub Shuffle(l As List) As List
|
||||
Dim tmpVal As String
|
||||
Dim Random As Int
|
||||
Private l1 As List
|
||||
l1.Initialize
|
||||
For i = 0 To l.Size - 1
|
||||
Random = Rnd(i, l.Size)
|
||||
tmpVal = l.get(i)
|
||||
l1.InsertAt(i, l.get(Random))
|
||||
l1.InsertAt(Random, tmpVal)
|
||||
Next
|
||||
Return l1
|
||||
End Sub
|
||||
@@ -1,24 +1,45 @@
|
||||
AppType=StandardJava
|
||||
Build1=Default,b4j.example
|
||||
File1=config.js
|
||||
File2=cover.png
|
||||
File3=genetic-algorithm.js
|
||||
File4=index.html
|
||||
File5=LICENSE
|
||||
File6=map.js
|
||||
File7=README.md
|
||||
File8=result.html
|
||||
File9=style.css
|
||||
FileGroup1=Default Group
|
||||
FileGroup2=Default Group
|
||||
FileGroup3=Default Group
|
||||
FileGroup4=Default Group
|
||||
FileGroup5=Default Group
|
||||
FileGroup6=Default Group
|
||||
FileGroup7=Default Group
|
||||
FileGroup8=Default Group
|
||||
FileGroup9=Default Group
|
||||
Group=Default Group
|
||||
Library1=compressstrings
|
||||
Library10=byteconverter
|
||||
Library2=jcore
|
||||
Library3=jfx
|
||||
Library4=jokhttputils2
|
||||
Library5=jrandomaccessfile
|
||||
Library6=jserver
|
||||
Library7=json
|
||||
Library8=jsql
|
||||
Library9=nhcalculatehash
|
||||
Module1=DBRequestManager
|
||||
Module2=delDB
|
||||
Module3=Mapa
|
||||
Module4=rutaCompleta
|
||||
Module5=Ruteador
|
||||
NumberOfFiles=0
|
||||
NumberOfLibraries=10
|
||||
NumberOfModules=5
|
||||
Library1=byteconverter
|
||||
Library10=nhcalculatehash
|
||||
Library11=javaobject
|
||||
Library2=compressstrings
|
||||
Library3=jcore
|
||||
Library4=jfx
|
||||
Library5=jokhttputils2
|
||||
Library6=jrandomaccessfile
|
||||
Library7=jserver
|
||||
Library8=json
|
||||
Library9=jsql
|
||||
Module1=Ayuda
|
||||
Module2=DBRequestManager
|
||||
Module3=delDB
|
||||
Module4=Genetic_Algorithm
|
||||
Module5=Mapa
|
||||
Module6=rutaCompleta
|
||||
Module7=Ruteador
|
||||
NumberOfFiles=9
|
||||
NumberOfLibraries=11
|
||||
NumberOfModules=7
|
||||
Version=10
|
||||
@EndOfDesignText@
|
||||
#Region Project Attributes
|
||||
@@ -38,7 +59,7 @@ Version=10
|
||||
#End Region
|
||||
|
||||
Sub Process_Globals
|
||||
Private srvr As Server
|
||||
Dim srvr As Server
|
||||
Dim db As SQL
|
||||
' Dim fx As JFX
|
||||
Dim punteoLista As List
|
||||
@@ -52,6 +73,7 @@ Sub Process_Globals
|
||||
' Dim estePunto() As String
|
||||
Dim error As String = ""
|
||||
Dim msg As String = ""
|
||||
Dim hash As String = ""
|
||||
End Sub
|
||||
|
||||
Sub AppStart (Args() As String)
|
||||
@@ -72,9 +94,7 @@ Sub AppStart (Args() As String)
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
|
||||
|
||||
|
||||
' Log($"ARGS=${DBRIp}:${DBRPort}"$)
|
||||
Log("Server Port=" & srvr.Port)
|
||||
ts.Initialize
|
||||
@@ -85,12 +105,20 @@ Sub AppStart (Args() As String)
|
||||
srvr.AddHandler("/mapa", "Mapa", False)
|
||||
srvr.AddHandler("/rutacompleta", "rutaCompleta", False)
|
||||
srvr.AddHandler("/borrar", "delDB", False)
|
||||
srvr.AddHandler("/ayuda", "Ayuda", False)
|
||||
srvr.AddHandler("/help", "Ayuda", False)
|
||||
srvr.AddHandler("/h", "Ayuda", False)
|
||||
srvr.AddHandler("/ga", "Genetic_Algorithm", False)
|
||||
|
||||
|
||||
Log(File.ListFiles(File.DirApp))
|
||||
Dim jo As JavaObject = srvr
|
||||
jo.GetFieldJO("context").RunMethodJO("getMimeTypes", Null).RunMethod("addMimeMapping", Array("kml", "text/xml"))
|
||||
|
||||
srvr.Start
|
||||
StartMessageLoop
|
||||
'open browser and navigate to: http://127.0.0.1:51042/
|
||||
|
||||
|
||||
|
||||
End Sub
|
||||
|
||||
#Region Shared Files
|
||||
@@ -153,7 +181,7 @@ Sub creaTablas(params As Map)
|
||||
Log(params)
|
||||
Private almacen As String = params.Get("almacen")
|
||||
Private estasCoords As String = params.Get("coords")
|
||||
Private hash As String = params.Get("hash")
|
||||
hash = params.Get("hash")
|
||||
Private ruta As String = $"${params.Get("ruta")}A${almacen}_${hash}"$
|
||||
db.BeginTransaction
|
||||
Try
|
||||
@@ -281,6 +309,10 @@ Sub generaMatrizOSRM(ruta As String) As ResumableSub 'ignore
|
||||
If j.Success Then
|
||||
' Log(j.GetString)
|
||||
Private j0 As String = j.GetString
|
||||
Else
|
||||
Log($"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ${CRLF} ${j.ErrorMessage}"$)
|
||||
If error = "" Then error = j.ErrorMessage
|
||||
Log($"######################### ${error}"$)
|
||||
End If
|
||||
j.Release
|
||||
' StopMessageLoop
|
||||
@@ -300,6 +332,7 @@ Sub generaMatrizOSRM(ruta As String) As ResumableSub 'ignore
|
||||
' fx.ShowExternalDocument($"http://router.project-osrm.org/table/v1/driving/${lasCoords}"$)
|
||||
Log("Matriz OSRM generada")
|
||||
Catch
|
||||
Log(456)
|
||||
Log(LastException)
|
||||
If error = "" Then error = LastException
|
||||
End Try
|
||||
@@ -394,7 +427,7 @@ Private Sub b_tiempos_Click
|
||||
' tiempos("R1")
|
||||
End Sub
|
||||
|
||||
'Regresa El tiempo y distancia de la ruta especificada.
|
||||
'Regresa El tiempo y distancia de la ruta especificada desde el API de OSRM.
|
||||
Sub tiempos(ruta As String) As ResumableSub 'ignore
|
||||
Log("#######################################################")
|
||||
Log("############# Main/tiempos ####################")
|
||||
@@ -422,6 +455,10 @@ Sub tiempos(ruta As String) As ResumableSub 'ignore
|
||||
' Log("RESPONSE:")
|
||||
' Log(j.GetString)
|
||||
Private j0 As String = j.GetString
|
||||
Else
|
||||
Log($"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ${CRLF} ${j.ErrorMessage}"$)
|
||||
If error = "" Then error = j.ErrorMessage
|
||||
Log($"######################### ${error}"$)
|
||||
End If
|
||||
j.Release
|
||||
' StopMessageLoop
|
||||
@@ -434,7 +471,7 @@ Sub tiempos(ruta As String) As ResumableSub 'ignore
|
||||
'' Log(colroot)
|
||||
'' Next
|
||||
' Log("*****************************************")
|
||||
ts.Put(ruta, CreateMap("code":"KO", "duration":0, "distance":0, "puntos":0))
|
||||
ts.Put(ruta, CreateMap("code":"KO", "duration":0, "distance":0, "puntos":0, "mensaje":error))
|
||||
Try
|
||||
Private m As Map = js.NextObject
|
||||
' Log(m)
|
||||
@@ -446,11 +483,12 @@ Sub tiempos(ruta As String) As ResumableSub 'ignore
|
||||
' Log("Distance: " & rutas.Get("distance"))
|
||||
' Log("Legs: " & rutas.Get("legs").As(List).Size)
|
||||
' Log("Waypoints: " & waypoints.Size)
|
||||
ts.Put(ruta, CreateMap("code":"OK", "duration":rutas.Get("duration"), "distance":rutas.Get("distance"), "puntos":rutas.Get("legs").As(List).Size))
|
||||
ts.Put(ruta, CreateMap("code":"OK", "hash":hash, "duration":rutas.Get("duration"), "distance":rutas.Get("distance"), "puntos":rutas.Get("legs").As(List).Size))
|
||||
' Log(">>>>>>>>>>>>>>>>>>>>>>>>>>>" & ts)
|
||||
Catch
|
||||
Log(LastException)
|
||||
If error = "" Then error = LastException
|
||||
Log($"######################### ${error}"$)
|
||||
End Try
|
||||
End If
|
||||
Return 1
|
||||
@@ -635,7 +673,7 @@ Public Sub calculateDistance3(lat1 As Double, lon1 As Double, lat2 As Double, lo
|
||||
Return Round(Yards)
|
||||
Catch
|
||||
Log("CalcDistance " & LastException)
|
||||
if error = "" then error = LastException
|
||||
If error = "" Then error = LastException
|
||||
Return -1
|
||||
End Try
|
||||
End Sub
|
||||
|
||||
@@ -4,18 +4,24 @@ ModuleBookmarks2=
|
||||
ModuleBookmarks3=
|
||||
ModuleBookmarks4=
|
||||
ModuleBookmarks5=
|
||||
ModuleBookmarks6=
|
||||
ModuleBookmarks7=
|
||||
ModuleBreakpoints0=
|
||||
ModuleBreakpoints1=
|
||||
ModuleBreakpoints2=
|
||||
ModuleBreakpoints3=
|
||||
ModuleBreakpoints4=
|
||||
ModuleBreakpoints5=
|
||||
ModuleBreakpoints6=
|
||||
ModuleBreakpoints7=
|
||||
ModuleClosedNodes0=
|
||||
ModuleClosedNodes1=
|
||||
ModuleClosedNodes2=
|
||||
ModuleClosedNodes3=
|
||||
ModuleClosedNodes4=
|
||||
ModuleClosedNodes5=3
|
||||
NavigationStack=rutaCompleta,generaMatrizRuteoTiempos,85,0,rutaCompleta,tiempos,105,0,Main,calculateDistance3,607,0,Ruteador,tiempos,166,0,Main,ruteo,308,0,Ruteador,Handle,38,0,Main,creaTablas,162,6,Main,generaMatrizLocal,217,0,Ruteador,generaMatrizRuteoTiempos,67,6,Main,ruteoNearestInsertion,479,4
|
||||
ModuleClosedNodes4=5,6,8,9,10
|
||||
ModuleClosedNodes5=
|
||||
ModuleClosedNodes6=
|
||||
ModuleClosedNodes7=6,7
|
||||
NavigationStack=Ruteador,Class_Globals,9,4,Ruteador,Handle,28,0,Main,ruteoNearestNeighbor,466,0,Genetic_Algorithm,traeDistanciaDesdeMatriz,398,6,Main,Process_Globals,31,6,Main,creaTablas,143,0,Mapa,ruteoCompleto,167,4,Ruteador,generaMatrizRuteoTiempos,125,0,Ruteador,tiempos,194,0,Main,tiempos,441,4
|
||||
SelectedBuild=0
|
||||
VisibleModules=5,3,4,1,2
|
||||
VisibleModules=7,5,6,2,3,4,1
|
||||
|
||||
40
Ruteador.bas
40
Ruteador.bas
@@ -13,6 +13,8 @@ Sub Class_Globals
|
||||
Dim m, m2 As Map
|
||||
Dim getHash As CalculateHash
|
||||
Dim js As JSONGenerator
|
||||
Dim cuantosPuntos As Int = 0
|
||||
Dim elHash As String
|
||||
End Sub
|
||||
|
||||
Public Sub Initialize
|
||||
@@ -30,18 +32,31 @@ Sub Handle(req As ServletRequest, resp As ServletResponse)
|
||||
Log("##############################################################")
|
||||
' Log("q='"&req.GetParameter("q")&"'")
|
||||
' Log($"REQ: ${req.FullRequestURI}"$)
|
||||
Private elHash As String = getHash.CalculateTheHash(req.FullRequestURI)
|
||||
elHash = getHash.CalculateTheHash(req.FullRequestURI)
|
||||
' Log(elHash)
|
||||
Private ruta As String = req.GetParameter("r")
|
||||
Private almacen As String = req.GetParameter("a")
|
||||
Private coords As String = req.GetParameter("c")
|
||||
Private matriz As String = req.GetParameter("m")
|
||||
Private ayuda As String
|
||||
If req.GetParameter("h") <> "" Then ayuda = req.GetParameter("h")
|
||||
If req.GetParameter("h") <> "" Then ayuda = req.GetParameter("help")
|
||||
If req.GetParameter("h") <> "" Then ayuda = req.GetParameter("ayuda")
|
||||
Main.inicio = req.GetParameter("i")
|
||||
Main.final = req.GetParameter("f")
|
||||
If matriz <> "" And matriz <> "OSRM" Then matriz = ""
|
||||
' Log($"r: ${ruta}, a: ${almacen}, Coords: ${coords}"$)
|
||||
Private urlParams As Map
|
||||
If ruta <> "" And almacen <> "" And coords <> "" Then
|
||||
Log("|"&ayuda&"|"& req.GetParameter("h") & "|" )
|
||||
If ayuda <> "" Then
|
||||
resp.ContentType = "text/html"
|
||||
resp.Write($"Son necesarios los siguientes parametros:<br>
|
||||
* r - La ruta<br>
|
||||
* a - El almacen<br>
|
||||
* c - Lista de puntos (id_cliente,lon,lat) separadas por punto y coma, el primer punto de la lista, se considera el punto de INICIO de la ruta.<br>
|
||||
* m - La matriz a usar LOCAL u OSRM (Opcional, default local<br>
|
||||
* f - El destino final (id_cliente,lon,lat) de donde termina la ruta (Opcional)"$)
|
||||
else If ruta <> "" And almacen <> "" And coords <> "" Then
|
||||
If Main.final <> "" Then coords = coords & ";" & Main.final
|
||||
ruta = "R" & ruta
|
||||
urlParams.Initialize
|
||||
@@ -77,6 +92,15 @@ Sub generaMatrizRuteoTiempos(r As String, resp As ServletResponse, ruta As Strin
|
||||
Log("############################################################################")
|
||||
Try
|
||||
'Generamos la matriz
|
||||
Private p As ResultSet = Main.db.ExecQuery($"select count(id) as cuantosPuntos from ${r}_puntos"$)
|
||||
Do While p.NextRow ' Revisamos que sean MENOS de 100 puntos, si no, usamos la matriz LOCAL.
|
||||
cuantosPuntos = p.GetInt("cuantosPuntos")
|
||||
Loop
|
||||
If cuantosPuntos > 98 Then
|
||||
If matriz = "OSRM" Then Main.msg = "Mas de 100 puntos, usamos matriz LOCAL"
|
||||
matriz = ""
|
||||
End If
|
||||
Log($"#### PUNTOS: ${cuantosPuntos}"$)
|
||||
If matriz = "OSRM" Then
|
||||
Wait for(Main.generaMatrizOSRM(r)) Complete (Result As Int)
|
||||
Else
|
||||
@@ -105,6 +129,7 @@ Sub generaMatrizRuteoTiempos(r As String, resp As ServletResponse, ruta As Strin
|
||||
If matriz = "" Then tempMap.Put("api", "Local")
|
||||
'Ponemos la ruta, almacen, tiempos, distancias y la lista de las coordenadas en un mapa para regresarla en un JSON.
|
||||
tempMap.Put("code", "OK")
|
||||
tempMap.Put("hash", elHash)
|
||||
tempMap.Put("ruta", ruta)
|
||||
tempMap.Put("almacen", almacen)
|
||||
tempMap.Put("duration", ts.Get("duration"))
|
||||
@@ -112,6 +137,7 @@ Sub generaMatrizRuteoTiempos(r As String, resp As ServletResponse, ruta As Strin
|
||||
tempMap.Put("puntos", ts.Get("puntos"))
|
||||
tempMap.Put("coords", listCoords)
|
||||
tempMap.Put("mensaje", Main.msg)
|
||||
If Main.error <> "" Then tempMap.Put("mensaje", Main.error)
|
||||
If tempMap.get("puntos") = 0 Then tempMap.Put("code", "KO")
|
||||
' Log(tempMap)
|
||||
js.Initialize(tempMap)
|
||||
@@ -132,6 +158,7 @@ Sub generaMatrizRuteoTiempos(r As String, resp As ServletResponse, ruta As Strin
|
||||
tempMap.Put("puntos", 0)
|
||||
tempMap.Put("coords", "")
|
||||
tempMap.Put("mensaje", Main.msg)
|
||||
If Main.error <> "" Then tempMap.Put("mensaje", Main.error)
|
||||
' Log(tempMap)
|
||||
js.Initialize(tempMap)
|
||||
StopMessageLoop
|
||||
@@ -156,18 +183,22 @@ Sub tiempos(r As String, resp As ServletResponse, ruta As String, almacen As Str
|
||||
Private listCoords As List
|
||||
listCoords.Initialize
|
||||
Private coords2 As String = ""
|
||||
Private coords3 As String = ""
|
||||
Do While p.NextRow
|
||||
listCoords.Add(CreateMap("pos":p.GetString("pos"), "id":p.GetString("id"), "lat":p.GetString("lat"), "lon":p.GetString("lon")))
|
||||
If coords2 = "" Then
|
||||
coords2 = $"${p.GetString("lon")},${p.GetString("lat")}"$
|
||||
coords3 = $"${p.GetString("id")},${p.GetString("lon")},${p.GetString("lat")}"$
|
||||
Else
|
||||
coords2 = $"${coords2}:${p.GetString("lon")},${p.GetString("lat")}"$
|
||||
coords3 = $"${coords3};${p.GetString("id")},${p.GetString("lon")},${p.GetString("lat")}"$
|
||||
End If
|
||||
Loop
|
||||
Main.db.Close
|
||||
tempMap.Put("api", matriz)
|
||||
If matriz = "" Then tempMap.Put("api", "Local")
|
||||
tempMap.Put("code", "OK")
|
||||
tempMap.Put("hash", elHash)
|
||||
tempMap.Put("ruta", ruta)
|
||||
tempMap.Put("almacen", almacen)
|
||||
tempMap.Put("duration", ts.Get("duration"))
|
||||
@@ -175,6 +206,7 @@ Sub tiempos(r As String, resp As ServletResponse, ruta As String, almacen As Str
|
||||
tempMap.Put("puntos", ts.Get("puntos"))
|
||||
tempMap.Put("coords", listCoords)
|
||||
tempMap.Put("mensaje", Main.msg)
|
||||
If Main.error <> "" Then tempMap.Put("mensaje", Main.error)
|
||||
If tempMap.get("puntos") = 0 Then tempMap.Put("code", "KO")
|
||||
' Log(tempMap)
|
||||
js.Initialize(tempMap)
|
||||
@@ -184,7 +216,9 @@ Sub tiempos(r As String, resp As ServletResponse, ruta As String, almacen As Str
|
||||
resp.ContentType = "text/html"
|
||||
resp.Write(js.ToString)
|
||||
Log("###################################################################" & CRLF)
|
||||
Log($"http://keymon.lat:9001/kmz.php?a=1&c=${coords2}"$)
|
||||
Log($"http://keymon.lat:${Main.srvr.port}/ga?c=${coords3}"$)
|
||||
Log("###################################################################" & CRLF)
|
||||
Log($"http://keymon.lat:${Main.srvr.port}/kmz.php?a=1&c=${coords2}"$)
|
||||
Log("###################################################################" & CRLF)
|
||||
Log("Liga para ver la ruta en mapa:" & CRLF)
|
||||
Log($"https://osm.quelltextlich.at/viewer-js.html?kml_url=http://keymon.lat:9001/kmz.php?c=${coords2}"$)
|
||||
|
||||
37
ayuda.bas
Normal file
37
ayuda.bas
Normal file
@@ -0,0 +1,37 @@
|
||||
B4J=true
|
||||
Group=Default Group
|
||||
ModulesStructureVersion=1
|
||||
Type=Class
|
||||
Version=10
|
||||
@EndOfDesignText@
|
||||
Sub Class_Globals
|
||||
Private mreq As ServletRequest 'ignore
|
||||
Private mresp As ServletResponse 'ignore
|
||||
End Sub
|
||||
|
||||
'Initializes the object. You can add parameters to this method if needed.
|
||||
Public Sub Initialize
|
||||
|
||||
End Sub
|
||||
|
||||
'Resumable Subs (wait for / sleep) in server handlers
|
||||
'Resumable subs can only work when there is a message queue.
|
||||
'By default, server handlers end when the Handle sub is completed. They do not create a message loop.
|
||||
'If you want to wait for an event then you need to call StartMessageLoop and later StopMessageLoop.
|
||||
'https://www.b4x.com/android/forum/threads/resumable-subs-wait-for-sleep-in-server-handlers.81833/
|
||||
Sub Handle(req As ServletRequest, resp As ServletResponse)
|
||||
Log("##############################################################")
|
||||
Log("############# Ayuda/Handle ########################")
|
||||
Log("##############################################################")
|
||||
resp.ContentType = "text/html"
|
||||
resp.Write($"Son necesarios los siguientes parametros:<br>
|
||||
* r - La ruta<br>
|
||||
* a - El almacen<br>
|
||||
* c - Lista de puntos (id_cliente,lon,lat) separadas por punto y coma, el primer punto de la lista, se considera el punto de INICIO de la ruta.<br>
|
||||
* m - La matriz a usar LOCAL u OSRM (Opcional, default LOCAL)<br>
|
||||
* f - El destino final (id_cliente,lon,lat) de donde termina la ruta (Opcional)<br><br>
|
||||
Ej.: http://localhost:${Main.srvr.port}/ruteador?m=LOCAL&r=114&a=68&c=CEDIS,-98.73952937,20.03334961;TIENDA1,-98.73952937,20.03334961<br><br>
|
||||
Tambien se puede escificar el parametro <b>f</b>, que especifica que la ruta termina en ese punto.
|
||||
|
||||
"$)
|
||||
End Sub
|
||||
Reference in New Issue
Block a user