From 291ee94f977eddf2ba7b7f585134d370911c89f7 Mon Sep 17 00:00:00 2001 From: John Heberty de Freitas <46422955+JohnHeberty@users.noreply.github.com> Date: Sun, 24 Apr 2022 12:05:32 -0300 Subject: [PATCH 1/2] =?UTF-8?q?Atualiza=C3=A7=C3=A3o=20de=20Capacidade?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Professor, está atualização contempla a capacidade da frota, e seu funcionamento esta da seguinte maneira: 1° - Ordena as capacidades do maior para o menor 2° - Ordena os cluster do maior para o menor 3° - Passa os parâmetros para o Carke Wright do maior cluster para frota de maior capacidade, sucessivamente na ordem das duas listas do passo 1° e 2°. OBS: os parâmetros de capacidade [5,1,1] não necessariamente gera uma rota com [5, 1, 1] de capacidade, pois isso depende do kmeans, se o cluster conter [5, 1, 1] de alunos, o router modificado irá fazer a rota [5, 1, 1] de capacidade, caso contrario irá criar uma nova rota. Rodei o código varias vezes e algumas delas aparece rotas [5, 1, 1] mas e raro. OBS DE MELHORIA: O Clarke Wright e rodado uma vez para cada cluster e gera as rotas mais econômicas para cada cluster, seria interessante se roda-se mais uma vez para os resultados finais de todos os cluster. Exemplo para o caso de capacidade [5,1,1], onde o kmeans gera um cluster [4,2,1], isso implica em que a frota com capacidade 5 atende o cluster com 4 alunos, mas a frota com capacidade 1 não atende o cluster com 2 alunos, e isso implica que sera gerado mais uma rota no final, deixando 4 rotas, sendo que essa solução final não e a mais interessante, já que se a frota com a capacidade de 5 tem uma vaga sobrando e poderia levar mais um aluno e evitaria fazer uma rota a mais. --- src/index.js | 9 +++- src/main/routing/routing-optimization.js | 50 ++++++++++++++---- src/renderer/img/icones/lancha-marcador2.png | Bin 0 -> 1729 bytes src/renderer/img/icones/onibus-marcador2.png | Bin 0 -> 2054 bytes .../modules/rota/rota-sugestao-ctrl.js | 12 ++--- 5 files changed, 54 insertions(+), 17 deletions(-) create mode 100644 src/renderer/img/icones/lancha-marcador2.png create mode 100644 src/renderer/img/icones/onibus-marcador2.png diff --git a/src/index.js b/src/index.js index 9596f42..4f60b52 100644 --- a/src/index.js +++ b/src/index.js @@ -228,9 +228,14 @@ ipcMain.on("start:route-generation", (event, routingArgs) => { nodes: {}, dist: {}, cost: {} } - let minNumVehicles = Math.max(routingArgs.numVehicles, Math.floor(routingArgs.stops.length / routingArgs.maxCapacity)); + type_Capacity = typeof routingArgs.maxCapacity; + if (type_Capacity !== 'object') { + routingArgs.maxCapacity = [Number(routingArgs.maxCapacity)]; + } + routingArgs.maxCapacity.sort((a,b)=> b-a); + let minNumVehicles = Math.max(routingArgs.numVehicles, Math.floor(routingArgs.stops.length / routingArgs.maxCapacity[0])); routingArgs.numVehicles = minNumVehicles; - routeOptimizer.optimize(cachedODMatrix, routingArgs) + routeOptimizer.optimize(cachedODMatrix, routingArgs); }) // Evento chamado pelo nosso worker quando ele terminar de gerar a rota diff --git a/src/main/routing/routing-optimization.js b/src/main/routing/routing-optimization.js index fc6c2a9..1297909 100644 --- a/src/main/routing/routing-optimization.js +++ b/src/main/routing/routing-optimization.js @@ -6,6 +6,7 @@ var ClarkeWrightSchoolBusRouting = require("./clarke-wright-schoolbus-routing.js var TwoOpt = require("./twoopt.js"); var SchoolBusKMeans = require("./kmeans.js"); var { Worker, isMainThread, parentPort, workerData } = require('worker_threads'); +const { toNumber } = require("lodash"); class RoutingOptimizationWorker { constructor(cachedODMatrix, routingParams, spatialiteDB) { @@ -45,6 +46,34 @@ class RoutingOptimizationWorker { return stops; } + SortClustersMaxToMin(clusterizedStops){ + let ClustersSorted = {}; + for (let i = 0; i < clusterizedStops.length; i++) { + let clusterStops = clusterizedStops[i]; + let countPassagers = 0; + for (let z = 0; z < clusterStops.length; z++) { + countPassagers = countPassagers + clusterStops[z].passengers; + } + ClustersSorted[countPassagers] = clusterStops; + } + //console.log("ClustersSorted = ",ClustersSorted); + + let IndexByCluester = Array(); + Object.keys(ClustersSorted).forEach((index)=>{ + IndexByCluester.push(Number(index)); + }); + IndexByCluester.sort((a,b)=> b-a); + //console.log("IndexByCluester = ",IndexByCluester); + + let SortClusters = Array(); + for (let i = 0; i < IndexByCluester.length; i++) { + SortClusters.push(ClustersSorted[IndexByCluester[i]]); + } + + //console.log("SortClusters = ",SortClusters); + return SortClusters; + } + optimize() { return new Promise((resolve, reject) => { // Activate spatial db @@ -57,33 +86,37 @@ class RoutingOptimizationWorker { let busRoutes = new Array(); let kmeans = new SchoolBusKMeans(this.routingParams); let routingGraph; + let IterCapacity = 0; kmeans.partition(this.routingParams["numVehicles"]) .then(clusters => { let clusterizedStops = new Array(); clusters.forEach((c) => clusterizedStops.push(this.getStops(c.cluster))) + clusterizedStops = this.SortClustersMaxToMin(clusterizedStops); let clarkAlgorithmsPromise = new Array(); clusterizedStops.forEach((cs) => { let param = Object.assign({}, this.routingParams); param["stops"] = cs; + param["maxCapacity"] = this.routingParams["maxCapacity"][IterCapacity]; // Deixar apenas as escolas que atendem os alunos no conjunto - let clusterSchoolsSet = new Set() - cs.forEach(student => clusterSchoolsSet.add(student["school"])) - let clusterSchools = new Array() + let clusterSchoolsSet = new Set(); + cs.forEach(student => clusterSchoolsSet.add(student["school"])); + let clusterSchools = new Array(); this.routingParams.schools.forEach(school => { if (clusterSchoolsSet.has(school["key"])) { clusterSchools.push(school); } - }) + }); param["schools"] = clusterSchools; let cwalg = new ClarkeWrightSchoolBusRouting(this.cachedODMatrix, param, this.spatialiteDB); clarkAlgorithmsPromise.push(cwalg.spatialRoute()); routers.push(cwalg); - }) - + IterCapacity++; + }); + // let schoolBusRouter = new ClarkeWrightSchoolBusRouting(this.routingParams, this.spatialiteDB); // schoolBusRouter.spatialRoute().then((busRoutes) => { return Promise.all(clarkAlgorithmsPromise) @@ -164,7 +197,6 @@ class RoutingOptimizationWorker { }; } - if (isMainThread) { module.exports = class RoutingOptimization { constructor(app, dbPath) { @@ -218,12 +250,12 @@ if (isMainThread) { .then((res) => { console.log("WORKER FINISHED") parentPort.postMessage({ error: false, result: res }) - // process.exit(0) + //process.exit(0) }) .catch((err) => { console.log("WORKER ERROR") parentPort.postMessage({ error: true, result: err }) - // process.exit(1) + //process.exit(1) }) }) diff --git a/src/renderer/img/icones/lancha-marcador2.png b/src/renderer/img/icones/lancha-marcador2.png new file mode 100644 index 0000000000000000000000000000000000000000..76aac454b2abbc053ef5ba9bee57fecb4b5576dc GIT binary patch literal 1729 zcmV;y20rPx#1ZP1_K>z@;j|==^1poj532;bRa{vGf6951U69E94oEQKA23AQ#K~!i%y_#KY z6jc<*&)wb9mX_L5*w#?pLeLOtKu{n^V_IW;@Wp^J8Y@B#4;oF3K}|?}0VN=WPZNFA z3I&8jj0rLE1-}x52*nnN1`sy1p&*}1=|a0Z{?E*r*`3+h-I<+jf63{cb9Xy){`cN< z@12=d6p-X$y=a29!4|@1!)8QkJphl7$U`?6^75v*Ek~AEJ#5CIMFf`9Q>ntMNueH7~vj8Fnlc*!Pm}9UI944 zTPO~|s`ZK@=`W9=OCZ3X2)^b4i6JLB1;{_{g!!Fave?+Xky0vLj0nE=&U_+VgOje? z0SmlNFum1}(}Czp!|^YIW7r`vWsxNSU*zQJf(35*Ot!|>(alJ`;S|>sT@srOTafqy zPnEo|1RC>h+(7VKV{63&#pOh|#AxAcWuE5)%rMfzdE*57loHFAXR1+8Nu8gf{UnVvWSAli35FR#-3mRJ$52?LLLu657O{2#(Qe zXk7pl@y3kzHi0=a@oDU!1RKb=~Kbf-U(H+QcD(1-Pe&3%4TEXisA| zcA8~UQ(8FqE%_4KBrRfy1>mqSqpF;`8}`!eaD&v04ZJSoO=uHC#0?g}kNXPp?Ue0w zu_Dlt;R#O(ohHr#_*rFMj?}E8qctVjta`#zLK~b?*bwn_vdi$Zxvipfu;w!iq3k=X zd_)ondU*dq>N|gtPQ3XB-L07^KN>!B!`J`lM6rt%HbU%!r5?g2~MX6NCvSb~~i7-v-%rf6G%p{5P zC6hQ$5W_iaDC$i`DX!O|7v4d!m5-Uhcq8@v=(x8>*84@%6dms$6fYRhx5jC9^L6on zqW9HG+H5ux=Kw$A)@h6l(#$#M^q#N`!T2>sgYcl%+H%<*JW&ESef;do829pWfuGM? z%$$3M8k(wL=4HW z*)P5;1qCn=!EZ+R#YcL7F_t2Dw&8?z8S_rElGqJN>_xB-V8&tx=~@(4se7ej80TG! zUFHHW!84wEAQSY4{ig<{>4^j)=|Xd^&s?Ou;9GzRgrtA$q0u~u2>BGjvr8|^J=mCi zVeW1GQnUaQ2w|EiNo}D4T8yw-;KyK599QU{Dzq@^0rHKL@pGFn9oDLGPrDRe(GdL) XYIS9iT))1300000NkvXXu0mjfbdE2e literal 0 HcmV?d00001 diff --git a/src/renderer/img/icones/onibus-marcador2.png b/src/renderer/img/icones/onibus-marcador2.png new file mode 100644 index 0000000000000000000000000000000000000000..2d707fbbff8d9aac578edf6adbc32e9a0eb0fbf4 GIT binary patch literal 2054 zcmV+h2>JJkP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!~g&e!~vBn4jTXf2b)PmK~!i%&6#Oz z6lEC4pPAY1w%db3g%;Sh+gd861rf^qK{0AnJ}D7nQAAUX35f#6649Ut8e>%a2+;@$ zw zm+bF&2r`60CstRZmY~W|`KWA^4Mq4+{iw^RMpO;z3HCe$E z^jW9aXU8O_0sI47u{eTCRXQdYJL(9=utja^V>pCZ@Sma#eEqpjFieKC5s>WW_VFfyEqr1C&)7KK;6*GvJReXF^9!It0Yn6Y_45L>{{9WdEOw12SdTINy}i(PRn_%@fuP14 zj^q4f!1RR@ncy;U)6RSzA7d~f)Nr=$44kd4Rn&C8UeTp`;|qpBN-nq^>%cwhY1U(! zelnna$Fa!y0>E()ptuYAd~QSYv$< zY#e)Hc)$nOXIPOUR-qF={0Oq7Zg?)&HKoK4gH?|{qSS+{5GTM;;U+BUInur2FjOZU zQ0gX-trlAmM=2?0b@kXmw-Iq!GuQw&S$nJuH_+8d(+XE-{MUW8N9m)-ljBgI_INC# z_&_dXq|KPmKRHL)Q0U%s+{kn0qnwae;Dnr9hbk8Qc)oVUfR1be- zAEM}fUKbCScpziNBg9M+y%xa|+%O_m9()V$W1*d048Pk3r}r%c(G!|zj#bT&Rl+8! z4kJF}Oyz3*bolqDT-L(LZ5Lt1rn;EJhv)cRTbB8Pmv2!97ULX{V_q$Ozr6swL!o@A z@bUAI{eX6yo8j`Q9BBAfxl~ZFrTO8po%H>mKDhE+v{~)tn-<*)UM)tp#Qw`S>z7((ITeAtY|=ctI^ssC95 z_i*STOmSWV`}9H9N{qqYRB*LUVJ!f`Dnb78KGq6>Dg0YomU`*S77d052t5;$6i^N} zz7aR;nNVa5zRDYgF)tYm!Xhm=`KBc>1Qukhlg2G(k6ahfu*Ayooe{ zt4$+L*b2QdAB}eJ*MUuJx&WguK$Ojnj+S)9v?ay-f-X_Kw9Y44?TgI>PndcG;o#e# zqt$lQi>TyrdJ{fO52^*hvg?iV;e<|z2^$y%jZgweCMwXx0yM!TXhNoq3A4(>f?z#> ziCN6-&4@7@808!J84$YLoPN>!Q17+2Jq`!gh_o kTTa?jGTSL79y Date: Wed, 4 May 2022 10:59:27 -0300 Subject: [PATCH 2/2] =?UTF-8?q?Corre=C3=A7=C3=A3o=20Bug=20Array=20de=20Cap?= =?UTF-8?q?acidade=20#97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tinha um bug ao alternar de frota homogênea para heterogênea, o script anterior tentava iterar sobre um numero inteiro. --- .../clarke-wright-schoolbus-routing.js | 1 + src/main/routing/routing-optimization.js | 26 ++++++++++++++++--- .../modules/rota/rota-sugestao-ctrl.js | 8 +++--- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/main/routing/clarke-wright-schoolbus-routing.js b/src/main/routing/clarke-wright-schoolbus-routing.js index b91b917..3658db5 100644 --- a/src/main/routing/clarke-wright-schoolbus-routing.js +++ b/src/main/routing/clarke-wright-schoolbus-routing.js @@ -112,6 +112,7 @@ class ClarkeWrightSchoolBusRouting { // console.log("PASSENGERS", totalPassengers, "MAX CAPACITY", this.maxCapacity) // console.log("TRAV DISTANCE", totalTravDistance, "MAX DIST", this.maxTravDist) // console.log("TRAV TIME", totalTravTime, "MAX TIME", this.maxTravTime) + // console.log("\n") // We can merge! let canMerge = false; diff --git a/src/main/routing/routing-optimization.js b/src/main/routing/routing-optimization.js index 1297909..8592847 100644 --- a/src/main/routing/routing-optimization.js +++ b/src/main/routing/routing-optimization.js @@ -14,6 +14,15 @@ class RoutingOptimizationWorker { this.routingParams = routingParams; this.spatialiteDB = spatialiteDB; this.reverseMap = new Map(); + + // IDENTIFICANDO O MODO DE SOLUÇÃO + if (typeof this.routingParams["maxCapacity"] == typeof []) { + this.heterogeneous = true; + console.log("\n *** FROTA HETEROGÊNEA ***\n") + } else { + this.heterogeneous = false; + console.log("\n *** FROTA HOMOGÊNEA ***\n") + } routingParams["stops"].forEach((s) => { let key = Number(s["lat"]).toFixed(10) + "-" + Number(s["lng"]).toFixed(10); @@ -92,14 +101,23 @@ class RoutingOptimizationWorker { .then(clusters => { let clusterizedStops = new Array(); clusters.forEach((c) => clusterizedStops.push(this.getStops(c.cluster))) - clusterizedStops = this.SortClustersMaxToMin(clusterizedStops); + // CASO PARTICULAR PARA FROTA HETEROGÊNEA + if (this.heterogeneous == true) { + clusterizedStops = this.SortClustersMaxToMin(clusterizedStops); + } + let clarkAlgorithmsPromise = new Array(); clusterizedStops.forEach((cs) => { let param = Object.assign({}, this.routingParams); param["stops"] = cs; - param["maxCapacity"] = this.routingParams["maxCapacity"][IterCapacity]; + // CASO PARTICULAR PARA FROTA HETEROGÊNEA + if (this.heterogeneous == true) { + param["maxCapacity"] = this.routingParams["maxCapacity"][IterCapacity]; + IterCapacity++; + } + // Deixar apenas as escolas que atendem os alunos no conjunto let clusterSchoolsSet = new Set(); cs.forEach(student => clusterSchoolsSet.add(student["school"])); @@ -110,11 +128,11 @@ class RoutingOptimizationWorker { } }); param["schools"] = clusterSchools; - + let cwalg = new ClarkeWrightSchoolBusRouting(this.cachedODMatrix, param, this.spatialiteDB); clarkAlgorithmsPromise.push(cwalg.spatialRoute()); routers.push(cwalg); - IterCapacity++; + }); // let schoolBusRouter = new ClarkeWrightSchoolBusRouting(this.routingParams, this.spatialiteDB); diff --git a/src/renderer/modules/rota/rota-sugestao-ctrl.js b/src/renderer/modules/rota/rota-sugestao-ctrl.js index 841b751..cb0d643 100644 --- a/src/renderer/modules/rota/rota-sugestao-ctrl.js +++ b/src/renderer/modules/rota/rota-sugestao-ctrl.js @@ -939,11 +939,11 @@ function initSimulation() { // Juntar dados em um objeto // Prof. deixei assim para facilitar sua correção os códigos original estão ao lado. let routeGenerationInputData = { - "maxTravDist": 9999999*1000,//Number($("#maxDist").val()) * 1000, - "maxTravTime": 9999999*60,//Number($("#maxTime").val()) * 60, + "maxTravDist": 999999999,//Number($("#maxDist").val()) * 1000, + "maxTravTime": 999999999,//Number($("#maxTime").val()) * 60, "optTarget": "maxTravDist", - "numVehicles": 3,//Number($("#numVehicles").val()), - "maxCapacity": [5, 1, 1],//Number($("#maxCapacity").val()), + "numVehicles": 1,//Number($("#numVehicles").val()), + "maxCapacity": [4,1,1],//Number($("#maxCapacity").val()), "busSpeed": Number($("#velMedia").val()) / 3.6, // converte de km/h para m/s "garage": garagens, "stops": alunos,