diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..af94e9d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+**/Objects
+**/AutoBackups
\ No newline at end of file
diff --git a/DBRequestManager.bas b/DBRequestManager.bas
new file mode 100644
index 0000000..3885b7f
--- /dev/null
+++ b/DBRequestManager.bas
@@ -0,0 +1,272 @@
+B4A=true
+Group=Default Group
+ModulesStructureVersion=1
+Type=Class
+Version=6.8
+@EndOfDesignText@
+'Class module
+' Requiere RandomAccessFile, CompressStrings, ByteConverter y OkhttpUtils2
+Sub Class_Globals
+ Private mTarget As Object
+ Type DBResult (Tag As Object, Columns As Map, Rows As List)
+ Type DBCommand (Name As String, Parameters() As Object)
+ Private link As String
+ Private bc As ByteConverter
+ Private T_NULL = 0, T_STRING = 1, T_SHORT = 2, T_INT = 3, T_LONG = 4, T_FLOAT = 5 _
+ ,T_DOUBLE = 6, T_BOOLEAN = 7, T_BLOB = 8 As Byte
+ Private VERSION As Float = 0.9
+ Private tempArray(1) As Object
+ Dim jobTagAnterior As String = "" 'Mod por CHV - 211109
+End Sub
+
+'Target - The module that handles JobDone (usually Me).
+'ConnectorLink - URL of the Java server.
+Public Sub Initialize (Target As Object, ConnectorLink As String)
+ mTarget = Target
+ link = ConnectorLink
+End Sub
+
+'Sends a query request.
+'Command - Query name and parameters.
+'Limit - Maximum rows to return or 0 for no limit.
+'Tag - An object that will be returned in the result.
+'Timeout - The http request timeout in ms, or 0 if default (30 secs)
+Public Sub ExecuteQuery(Command As DBCommand, Limit As Int, Tag As Object, Timeout As Int) 'Mod por CHV, agregué el parametro Timeout - 211229
+ Dim j As HttpJob
+ Dim ms As OutputStream
+ Dim out2 As OutputStream = StartJob(j,ms, Tag)
+ WriteObject(Command.Name, out2)
+ WriteInt(Limit, out2)
+ WriteList(Command.Parameters, out2)
+ out2.Close
+ j.PostBytes(link & "?method=query", ms.ToBytesArray)
+ If Timeout <> 0 Then j.GetRequest.Timeout = Timeout
+End Sub
+
+'Executes a batch of (non-select) commands.
+'ListOfCommands - List of the commands that will be executes.
+'Tag - An object that will be returned in the result.
+Public Sub ExecuteBatch(ListOfCommands As List, Tag As Object)
+ Dim j As HttpJob
+ Dim ms As OutputStream
+ Dim out2 As OutputStream = StartJob(j,ms, Tag)
+ WriteInt(ListOfCommands.Size, out2)
+ For Each Command As DBCommand In ListOfCommands
+ WriteObject(Command.Name, out2)
+ WriteList(Command.Parameters, out2)
+ Next
+ out2.Close
+ j.PostBytes(link & "?method=batch", ms.ToBytesArray)
+End Sub
+
+'Similar to ExecuteBatch. Sends a single command.
+Public Sub ExecuteCommand(Command As DBCommand, Tag As Object)
+ ExecuteBatch(Array As DBCommand(Command), Tag)
+End Sub
+
+Private Sub StartJob(j As HttpJob, MemoryStream As OutputStream, Tag As Object) As OutputStream
+ j.Initialize("DBRequest", mTarget)
+ j.Tag = Tag
+ MemoryStream.InitializeToBytesArray(0)
+ Dim compress As CompressedStreams
+ Dim out As OutputStream = compress.WrapOutputStream(MemoryStream, "gzip")
+ WriteObject(VERSION, out)
+ Return out
+End Sub
+
+Private Sub WriteList(Parameters As List, out As OutputStream)
+ Dim data() As Byte
+ If Parameters = Null Or Parameters.IsInitialized = False Then
+ Dim Parameters As List
+ Parameters.Initialize
+ End If
+ data = bc.IntsToBytes(Array As Int(Parameters.Size))
+ out.WriteBytes(data, 0, data.Length)
+ For Each o As Object In Parameters
+ WriteObject(o, out)
+ Next
+End Sub
+
+Private Sub WriteObject(o As Object, out As OutputStream)
+ Dim data() As Byte
+ tempArray(0) = o
+ If tempArray(0) = Null Then
+ out.WriteBytes(Array As Byte(T_NULL), 0, 1)
+ Else If tempArray(0) Is Short Then
+ out.WriteBytes(Array As Byte(T_SHORT), 0, 1)
+ data = bc.ShortsToBytes(Array As Short(o))
+ Else If tempArray(0) Is Int Then
+ out.WriteBytes(Array As Byte(T_INT), 0, 1)
+ data = bc.IntsToBytes(Array As Int(o))
+ Else If tempArray(0) Is Float Then
+ out.WriteBytes(Array As Byte(T_FLOAT), 0, 1)
+ data = bc.FloatsToBytes(Array As Float(o))
+ Else If tempArray(0) Is Double Then
+ out.WriteBytes(Array As Byte(T_DOUBLE), 0, 1)
+ data = bc.DoublesToBytes(Array As Double(o))
+ Else If tempArray(0) Is Long Then
+ out.WriteBytes(Array As Byte(T_LONG), 0, 1)
+ data = bc.LongsToBytes(Array As Long(o))
+ Else If tempArray(0) Is Boolean Then
+ out.WriteBytes(Array As Byte(T_BOOLEAN), 0, 1)
+ Dim b As Boolean = 0
+ Dim data(1) As Byte
+ If b Then data(0) = 1 Else data(0) = 0
+ Else If GetType(tempArray(0)) = "[B" Then
+ data = o
+ out.WriteBytes(Array As Byte(T_BLOB), 0, 1)
+ WriteInt(data.Length, out)
+ Else 'If o Is String Then (treat all other values as string)
+ out.WriteBytes(Array As Byte(T_STRING), 0, 1)
+ data = bc.StringToBytes(o, "UTF8")
+ WriteInt(data.Length, out)
+ End If
+ If data.Length > 0 Then out.WriteBytes(data, 0, data.Length)
+End Sub
+
+Private Sub ReadObject(In As InputStream) As Object
+ Dim data(1) As Byte
+ In.ReadBytes(data, 0, 1)
+ Select data(0)
+ Case T_NULL
+ Return Null
+ Case T_SHORT
+ Dim data(2) As Byte
+ Return bc.ShortsFromBytes(ReadBytesFully(In, data, data.Length))(0)
+ Case T_INT
+ Dim data(4) As Byte
+ Return bc.IntsFromBytes(ReadBytesFully(In, data, data.Length))(0)
+ Case T_LONG
+ Dim data(8) As Byte
+ Return bc.LongsFromBytes(ReadBytesFully(In, data, data.Length))(0)
+ Case T_FLOAT
+ Dim data(4) As Byte
+ Return bc.FloatsFromBytes(ReadBytesFully(In, data, data.Length))(0)
+ Case T_DOUBLE
+ Dim data(8) As Byte
+ Return bc.DoublesFromBytes(ReadBytesFully(In, data, data.Length))(0)
+ Case T_BOOLEAN
+ Dim b As Byte = ReadByte(In)
+ Return b = 1
+ Case T_BLOB
+ Dim len As Int = ReadInt(In)
+ Dim data(len) As Byte
+ Return ReadBytesFully(In, data, data.Length)
+ Case Else
+ Dim len As Int = ReadInt(In)
+ Dim data(len) As Byte
+ ReadBytesFully(In, data, data.Length)
+ Return BytesToString(data, 0, data.Length, "UTF8")
+ End Select
+End Sub
+
+Private Sub ReadBytesFully(In As InputStream, Data() As Byte, Len As Int) As Byte()
+ Dim count = 0, read As Int
+ Do While count < Len And read > -1
+ read = In.ReadBytes(Data, count, Len - count)
+ count = count + read
+ Loop
+ Return Data
+End Sub
+
+Private Sub WriteInt(i As Int, out As OutputStream)
+ Dim data() As Byte
+ data = bc.IntsToBytes(Array As Int(i))
+ out.WriteBytes(data, 0, data.Length)
+End Sub
+
+Private Sub ReadInt(In As InputStream) As Int
+ Dim data(4) As Byte
+ Return bc.IntsFromBytes(ReadBytesFully(In, data, data.Length))(0)
+End Sub
+
+Private Sub ReadByte(In As InputStream) As Byte
+ Dim data(1) As Byte
+ In.ReadBytes(data, 0, 1)
+ Return data(0)
+End Sub
+
+'Handles the Job result and returns a DBResult.
+Public Sub HandleJob(Job As HttpJob) As DBResult
+ Dim start As Long = DateTime.Now 'ignore
+ Dim In As InputStream = Job.GetInputStream
+ Dim cs As CompressedStreams
+ In = cs.WrapInputStream(In, "gzip")
+ Dim serverVersion As Float = ReadObject(In) 'ignore
+ Dim method As String = ReadObject(In)
+ Dim table As DBResult
+ table.Initialize
+ table.Columns.Initialize
+ table.rows.Initialize
+ table.Tag = Job.Tag
+ If jobTagAnterior <> Job.Tag Then Log("HandleJob: '"&Job.Tag&"'") 'Mod por CHV - 211109
+ jobTagAnterior = Job.Tag 'Mod por CHV - 211109
+ If method = "query" Then
+ Dim numberOfColumns As Int = ReadInt(In)
+ For i = 0 To numberOfColumns - 1
+ table.Columns.Put(ReadObject(In), i)
+ Next
+ Do While ReadByte(In) = 1
+ Dim rowObjects(numberOfColumns) As Object
+ table.rows.Add(rowObjects)
+ For col = 0 To numberOfColumns - 1
+ Dim o As Object = ReadObject(In)
+ rowObjects(col) = o
+ Next
+ Loop
+ Else If method = "batch" Then
+ table.Columns.Put("AffectedRows", 0)
+ Dim rows As Int = ReadInt(In)
+ For i = 0 To rows - 1
+ table.rows.Add(Array As Object(ReadInt(In)))
+ Next
+ End If
+ In.Close
+' Log("HandleJob: " & (DateTime.Now - start))'Comentado por CHV - 211112
+ Return table
+End Sub
+'Reads a file and returns the file as a bytes array.
+Public Sub FileToBytes(Dir As String, FileName As String) As Byte()
+ Dim out As OutputStream
+ out.InitializeToBytesArray(0)
+ Dim In As InputStream = File.OpenInput(Dir, FileName)
+ File.Copy2(In, out)
+ out.Close
+ Return out.ToBytesArray
+End Sub
+'Converts an image to a bytes array (for BLOB fields).
+'Public Sub ImageToBytes(Image As Bitmap) As Byte()
+' Dim out As OutputStream
+' out.InitializeToBytesArray(0)
+' Image.WriteToStream(out, 100, "JPEG")
+' out.Close
+' Return out.ToBytesArray
+'End Sub
+''Converts a bytes array to an image (for BLOB fields).
+'Public Sub BytesToImage(bytes() As Byte) As Bitmap
+' Dim In As InputStream
+' In.InitializeFromBytesArray(bytes, 0, bytes.Length)
+' Dim bmp As Bitmap
+' bmp.Initialize2(In)
+' Return bmp
+'End Sub
+'Prints the table to the logs.
+Public Sub PrintTable(Table As DBResult)
+ Log("Tag: " & Table.Tag & ", Columns: " & Table.Columns.Size & ", Rows: " & Table.Rows.Size)
+ Dim sb As StringBuilder
+ sb.Initialize
+ For Each col In Table.Columns.Keys
+ sb.Append(col).Append(TAB)
+ Next
+ Log(sb.ToString)
+ For Each row() As Object In Table.Rows
+ Dim sb As StringBuilder
+ sb.Initialize
+ For Each record As Object In row
+ sb.Append(record).Append(TAB)
+ Next
+' ToastMessageShow(sb.ToString, True)
+ Next
+End Sub
+
+
\ No newline at end of file
diff --git a/GuessMyNumber.bas b/GuessMyNumber.bas
new file mode 100644
index 0000000..27df738
--- /dev/null
+++ b/GuessMyNumber.bas
@@ -0,0 +1,36 @@
+B4J=true
+Group=Default Group
+ModulesStructureVersion=1
+Type=Class
+Version=2.18
+@EndOfDesignText@
+'Class module
+Sub Class_Globals
+End Sub
+
+Public Sub Initialize
+
+End Sub
+
+Sub Handle(req As ServletRequest, resp As ServletResponse)
+ Try
+ If req.GetSession.HasAttribute("myNumber") = False Then
+ req.GetSession.SetAttribute("myNumber", Rnd(0, 101))
+ End If
+ Dim myNumber As Int = req.GetSession.GetAttribute("myNumber")
+ Dim n As String = req.GetParameter("number")
+ If IsNumber(n) = False Then
+ resp.Write("Please enter a valid number.")
+ Else
+ If n > myNumber Then
+ resp.Write("My number is smaller.")
+ Else If n < myNumber Then
+ resp.Write("My number is larger.")
+ Else
+ resp.Write("Well done!!!")
+ End If
+ End If
+ Catch
+ resp.SendError(500, "error....")
+ End Try
+End Sub
\ No newline at end of file
diff --git a/Mapa.bas b/Mapa.bas
new file mode 100644
index 0000000..e54a899
--- /dev/null
+++ b/Mapa.bas
@@ -0,0 +1,196 @@
+B4J=true
+Group=Default Group
+ModulesStructureVersion=1
+Type=Class
+Version=10
+@EndOfDesignText@
+'Class module
+Sub Class_Globals
+ Private mreq As ServletRequest 'ignore
+ Private mresp As ServletResponse 'ignore
+' Dim cmd As DBCommand
+ Dim getHash As CalculateHash
+ Dim js As JSONGenerator
+End Sub
+
+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("############# Mapa/Handle ################")
+ Log("##################################################")
+' Log("q='"&req.GetParameter("q")&"'")
+' Log($"REQ: ${req.FullRequestURI}"$)
+ Private elHash As String = 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")
+ 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
+ ruta = "R" & ruta
+ urlParams.Initialize
+ urlParams.Put("almacen", almacen)
+ urlParams.Put("coords", coords)
+ urlParams.Put("hash", elHash)
+ urlParams.Put("ruta", ruta)
+ Main.db.InitializeSQLite(File.DirApp, "kmt.db", True)
+
+' Si no existe la tabla del ruteo, la creamos.
+ If Not(checkIfTableExists($"${ruta}A${almacen}_${elHash}_punteo"$)) Then
+ Log($"Creamos tablas ruta ${ruta}, almacen ${almacen}"$)
+ Main.creaTablas(urlParams)
+ generaMatrizRuteoTiempos($"${ruta}A${almacen}_${elHash}"$, resp, ruta, almacen, matriz)
+ StartMessageLoop
+ Else 'Si ya existe, solo calculamos los tiempos y distancias.
+ tiempos($"${ruta}A${almacen}_${elHash}"$, resp, ruta, almacen, matriz)
+ StartMessageLoop
+ End If
+ Else
+ resp.ContentType = "text/html"
+ resp.Write("Hay un error en la solicitud, son necesarios los parametros:
* r - La ruta
* a - El almacen
* c - id_cliente,lon,lat separadas por punto y coma.
* m - La matriz a usar LOCAL u OSRM (Opcional, default local)") 'this file will be loaded from the www folder
+ End If
+End Sub
+
+Sub generaMatrizRuteoTiempos(r As String, resp As ServletResponse, ruta As String, almacen As String, matriz As String) As ResumableSub
+ Log("############################################################################")
+ Log("############# Mapa/generaMatrizRuteoTiempos ########################")
+ Log("############################################################################")
+ 'Generamos la matriz
+ If matriz = "OSRM" Then
+ Wait for(Main.generaMatrizOSRM(r)) Complete (Result As Int)
+ Else
+ Main.generaMatrizLocal(r)
+ End If
+ 'Generamos el ruteo
+ Main.ruteo($"${r}"$, matriz)
+' Wait for(Main.tiempos($"${r}"$)) Complete (Result As Int)
+' Private ts As Map = Main.ts.Get($"${r}"$)
+' Log(ts)
+ Private p As ResultSet = Main.db.ExecQuery($"select * from ${r}_punteo"$)
+ Private listCoords As String = ""
+ 'Ponemos el id de la tienda y las coordenadas en una lista para regresarla en un JSON.
+ Do While p.NextRow
+ If listCoords = "" Then
+ listCoords = $"${p.GetString("lon")},${p.GetString("lat")}"$
+ Else
+ listCoords = $"${listCoords}:${p.GetString("lon")},${p.GetString("lat")}"$
+ End If
+ Loop
+ Main.db.Close
+ StopMessageLoop
+ resp.ContentType = "text/html"
+
+ resp.Write($"Mapa"$)
+ Return 1
+End Sub
+
+Sub tiempos(r As String, resp As ServletResponse, ruta As String, almacen As String, matriz As String) As ResumableSub
+ Log("############################################################")
+ Log("############# Mapa/tiempos ########################")
+ Log("###########################################################")
+ Private p As ResultSet = Main.db.ExecQuery($"select * from ${r}_punteo"$)
+ Private listCoords As String = ""
+ Do While p.NextRow
+ If listCoords = "" Then
+ listCoords = $"${p.GetString("lon")},${p.GetString("lat")}"$
+ Else
+ listCoords = $"${listCoords}:${p.GetString("lon")},${p.GetString("lat")}"$
+ End If
+ Loop
+ Main.db.Close
+
+ Log("Iniciamos ruteoCompleto")
+ ruteoCompleto(r)
+
+ StopMessageLoop
+ resp.ContentType = "text/html"
+ resp.Write($"Mapa"$)
+ Return 1
+End Sub
+
+
+'Regresa la ruta esquina a esquina.
+Sub ruteoCompleto(ruta As String) As ResumableSub 'ignore
+ Log("#################################################################")
+ Log("############# Mapa/ruteoCompleto ########################")
+ Log("#################################################################")
+' Log("Tiempos: " & ruta)
+ Private c As ResultSet = Main.db.ExecQuery($"select * from ${ruta}_punteo"$)
+ Private estasCoords As String = ""
+ Private ts As Map
+ ts.Initialize
+ Do While c.NextRow
+ If estasCoords = "" Then
+ estasCoords = $"${c.GetString("lon")},${c.GetString("lat")}"$
+ Else
+ estasCoords = $"${estasCoords};${c.GetString("lon")},${c.GetString("lat")}"$
+ End If
+ Loop
+ Dim j As HttpJob
+ j.Initialize("", Me)
+ j.Download($"http://router.project-osrm.org/route/v1/driving/${estasCoords}?steps=true"$)
+ Wait For (j) JobDone(j As HttpJob)
+ If j.Success Then
+' Log(j.GetString)
+ Private j0 As String = j.GetString
+ End If
+ j.Release
+' StopMessageLoop
+ Private js1 As JSONParser
+ js1.Initialize(j0)
+' Log(js1)
+' For Each colroot As Map In js
+' Log(colroot)
+' Next
+' Log("*****************************************")
+' Log(js.NextObject)
+ Private m As Map = js1.NextObject
+' Private estatus As String = m.Get("code")
+ Private rutas As Map = m.Get("routes").as(List).Get(0)
+' Private waypoints As List = m.Get("waypoints")
+' Log("Response: " & estatus)
+' Log("Duration: " & rutas.Get("duration"))
+' Log("Distance: " & rutas.Get("distance"))
+' Log("Legs: " & rutas.Get("legs").As(List).Size)
+' Log("Waypoints: " & waypoints.Size)
+ Private steps As List
+ steps.Initialize
+ steps = rutas.Get("legs").as(List).get("steps")
+ Log("STEPS SIZE: " & steps.Size)
+ ts.Put(ruta, CreateMap("code":"Ok", "duration":rutas.Get("duration"), "distance":rutas.Get("distance"), "puntos":rutas.Get("legs").As(List).Size))
+' Log(">>>>>>>>>>>>>>>>>>>>>>>>>>>" & ts)
+ Return 1
+End Sub
+
+'Convierte una lista en un arreglo (array as object).
+Public Sub ListToArray(inList As List) As Object()
+ Dim OutArray(inList.Size) As Object
+ For i = 0 To inList.Size - 1
+ OutArray(i) = inList.Get(i)
+ Next
+ Return OutArray
+End Sub
+
+Sub checkIfTableExists(table As String) As Boolean
+' B4XPages.MainPage.db.InitializeSQLite(File.DirApp, "kmt.db", True)
+ Private r As ResultSet = Main.db.ExecQuery($"Select name FROM sqlite_master WHERE Type='table' AND name='${table}'"$)
+ If r.NextRow Then
+' B4XPages.MainPage.db.close
+' Log($"NAME: ${r.GetString("name")}"$)
+ Return True
+ Else
+' B4XPages.MainPage.db.close
+ Return False
+ End If
+End Sub
\ No newline at end of file
diff --git a/ResetMyNumber.bas b/ResetMyNumber.bas
new file mode 100644
index 0000000..f3c1f1a
--- /dev/null
+++ b/ResetMyNumber.bas
@@ -0,0 +1,18 @@
+B4J=true
+Group=Default Group
+ModulesStructureVersion=1
+Type=Class
+Version=2.18
+@EndOfDesignText@
+'Class module
+Sub Class_Globals
+
+End Sub
+
+Public Sub Initialize
+
+End Sub
+
+Sub Handle(req As ServletRequest, resp As ServletResponse)
+ req.GetSession.RemoveAttribute("myNumber")
+End Sub
\ No newline at end of file
diff --git a/Ruteador-NonUI.b4j b/Ruteador-NonUI.b4j
new file mode 100644
index 0000000..c2ada0d
--- /dev/null
+++ b/Ruteador-NonUI.b4j
@@ -0,0 +1,605 @@
+AppType=StandardJava
+Build1=Default,b4j.example
+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
+Version=10
+@EndOfDesignText@
+#Region Project Attributes
+ #CommandLineArgs:
+ #MergeLibraries: True
+ #AdditionalJar: sqlite-jdbc-3.7.2.jar
+ '###########################################################################################################
+ '###################### PULL #############################################################
+ 'Ctrl + click ide://run?file=%WINDIR%\System32\cmd.exe&Args=/c&Args=git&Args=pull
+ '###########################################################################################################
+ '###################### PUSH #############################################################
+ 'Ctrl + click ide://run?file=%WINDIR%\System32\WindowsPowerShell\v1.0\powershell.exe&Args=github&Args=..\..\
+ '###########################################################################################################
+ '###################### PUSH TORTOISE GIT #########################################################
+ 'Ctrl + click ide://run?file=%WINDIR%\System32\WindowsPowerShell\v1.0\powershell.exe&Args=TortoiseGitProc&Args=/command:commit&Args=/path:"./../"&Args=/closeonend:2
+ '###########################################################################################################
+#End Region
+
+Sub Process_Globals
+ Private srvr As Server
+ Dim db As SQL
+' Dim fx As JFX
+ Dim punteoLista As List
+ Dim algoritmo As Int = 1
+' Dim api As Int = 0
+' Dim matriz As String = ""
+' Dim urlParams As Map
+ Dim ts As Map
+' Dim coords As List
+' Dim estePunto() As String
+End Sub
+
+Sub AppStart (Args() As String)
+ srvr.Initialize("srvr")
+ srvr.Port = 9002
+ If(Args.Length > 0) Then
+ Log($"Args=${Args(0)}"$)
+ For i=0 To Args.Length -1
+ If(Args(i).StartsWith("portX=") Or Args(i).StartsWith("PortX=")) Then
+' DBRPort = Args(i).SubString(5)
+' Log($"Puerto de DBRequest = ${Args(i).SubString(5)}"$)
+ Else if (Args(i).StartsWith("ip=") Or Args(i).StartsWith("IP=")) Then
+' DBRIp = Args(i).SubString(3)
+' Log($"IP de DBRequest = ${Args(i).SubString(3)}"$)
+ Else if (Args(i).ToUpperCase.StartsWith("PORT=") Or Args(i).ToUpperCase.StartsWith("P=")) Then
+ srvr.Port = Args(i).SubString(Args(i).IndexOf("=")+1)
+ Log($"Puerto del servidor = ${Args(i).SubString(Args(i).IndexOf("="))}"$)
+ End If
+ Next
+ End If
+
+
+
+' Log($"ARGS=${DBRIp}:${DBRPort}"$)
+ Log("Server Port=" & srvr.Port)
+ ts.Initialize
+ srvr.StaticFilesFolder = File.Combine(File.DirApp, "www")
+ srvr.LogsFileFolder = File.Combine(File.DirApp, "logs")
+ srvr.LogsRetainDays = 15
+ srvr.AddHandler("/ruteador", "Ruteador", False)
+ srvr.AddHandler("/mapa", "Mapa", False)
+ srvr.AddHandler("/rutacompleta", "rutaCompleta", False)
+ srvr.AddHandler("/borrar", "delDB", False)
+ srvr.Start
+ StartMessageLoop
+ 'open browser and navigate to: http://127.0.0.1:51042/
+
+
+
+End Sub
+
+#Region Shared Files
+'#CustomBuildAction: folders ready, %WINDIR%\System32\Robocopy.exe,"..\..\Shared Files" "..\Files"
+'Ctrl + click to sync files: ide://run?file=%WINDIR%\System32\Robocopy.exe&args=..\..\Shared+Files&args=..\Files&FilesSync=True
+#End Region
+
+'Ctrl + click to export as zip: ide://run?File=%B4X%\Zipper.jar&Args=Project.zip
+
+Public Sub Initialize
+' B4XPages.GetManager.LogEvents = True
+End Sub
+
+'This event will be called once, before the page becomes visible.
+Private Sub B4XPage_CreatedX
+' urlParams.Initialize
+' ts.Initialize
+' Log(File.DirApp)
+' db.InitializeSQLite(File.DirApp, "kmt.db", True)
+'
+'' almacen.Initialize2("19.44598465518769", "-99.1818326916271") 'Mexico-España - Lago Iseo 128
+' db.ExecNonQuery("CREATE TABLE IF NOT EXISTS R1_puntos (id TEXT, nombre TEXT, lat TEXT, lon TEXT)")
+' db.ExecNonQuery("CREATE TABLE IF NOT EXISTS R1_punteo (pos TEXT, id TEXT, nombre TEXT, lat TEXT, lon TEXT)")
+' db.ExecNonQuery("CREATE TABLE IF NOT EXISTS R1_matriz (idT TEXT, t1 TEXT, t2 TEXT, t3 TEXT, t4 TEXT, t5 TEXT, t6 TEXT, t7 TEXT, t8 TEXT, t9 TEXT, t10 TEXT)")
+' db.ExecNonQuery("CREATE TABLE IF NOT EXISTS R1_matrizOSRM (idT TEXT, t1 TEXT, t2 TEXT, t3 TEXT, t4 TEXT, t5 TEXT, t6 TEXT, t7 TEXT, t8 TEXT, t9 TEXT, t10 TEXT)")
+'
+' 'Generamos la lista de puntos y la guardamos en la tabla "R1_puntos"
+' coords.Initialize
+' coords.AddAll(Array As String ("Mexico-España,19.44598465518769,-99.1818326916271", "Xochimilco 47,19.448171727202524,-99.1779942882756", "Little Caesars,19.449867997938245,-99.1833874413472", "El Globo,19.451633331080625,-99.18485729424397", "Bodega Aurrera,19.445747004224824,-99.18301691592744", "Wetter 76,19.446150110778017,-99.1936412539473", "Papeleria Progreso,19.443934235653053,-99.18575629823629", "La Esperanza,19.442779235275808,-99.19255124428338", "Modelo,19.440456467281724,-99.18896176081896", "Gringo,19.441000733767016,-99.1817225994711", "Pemex,19.439420250127483,-99.17486856671235"))
+'' db.ExecNonQuery("delete from R1_puntos")
+'' For a = 0 To coords.Size - 1
+'' estePunto = Regex.Split(",", coords.Get(a))
+'' db.ExecNonQuery($"insert into R1_puntos (id, nombre, lat, lon) values ('A${a}', '${estePunto(0)}', '${estePunto(1)}', '${estePunto(2)}')"$)
+'' Next
+' 'Creamos la tabla de la matriz con las columnas necesarias.
+' Try
+' db.ExecNonQuery($"drop table R1_matriz"$)
+' db.ExecNonQuery($"drop table R1_matrizOSRM"$)
+' db.ExecNonQuery("vacuum")
+' Catch
+' Log(LastException)
+' End Try
+' Private colsMatriz As String = "idT TEXT"
+' Private pp As ResultSet = db.ExecQuery("select * from R1_puntos")
+' Do While pp.NextRow
+' colsMatriz = $"${colsMatriz},'${pp.GetString("id")}' REAL"$
+' Loop
+' Log(colsMatriz)
+' db.ExecNonQuery($"create table if not exists R1_matriz (${colsMatriz})"$)
+' db.ExecNonQuery($"create table if not exists R1_matrizOSRM (${colsMatriz})"$)
+' 'Generamos la matriz
+' b_generaMatriz_Click
+End Sub
+
+Sub creaTablas(params As Map)
+ 'Creamos las tablas de la ruta con las columnas necesarias.
+ Log("##########################################################")
+ Log("############# Main/creaTablas ####################")
+ Log("##########################################################")
+ Log(params)
+ Private almacen As String = params.Get("almacen")
+ Private estasCoords As String = params.Get("coords")
+ Private hash As String = params.Get("hash")
+ Private ruta As String = $"${params.Get("ruta")}A${almacen}_${hash}"$
+ Try
+' Log($"drop table if exists ${ruta}_matriz"$)
+ db.ExecNonQuery($"drop table if exists ${ruta}_matriz"$)
+' Log($"drop table if exists ${ruta}_matrizOSRM"$)
+ db.ExecNonQuery($"drop table if exists ${ruta}_matrizOSRM"$)
+' Log($"drop table if exists ${ruta}_puntos"$)
+ db.ExecNonQuery($"drop table if exists ${ruta}_puntos"$)
+ Catch
+ Log(LastException)
+ End Try
+ db.ExecNonQuery($"create table if not exists ${ruta}_puntos (id TEXT, nombre TEXT, lat TEXT, lon TEXT)"$)
+' Log($"create table if not exists ${ruta}_puntos (id TEXT, nombre TEXT, lat TEXT, lon TEXT)"$)
+ db.ExecNonQuery($"create table if not exists ${ruta}_punteo (pos TEXT, id TEXT, nombre TEXT, lat TEXT, lon TEXT)"$)
+' Log($"create table if not exists ${ruta}_punteo (pos TEXT, id TEXT, nombre TEXT, lat TEXT, lon TEXT)"$)
+
+ Private f() As String = Regex.Split(";", estasCoords)
+ For i = 0 To f.Length - 1
+' Log(f(i))
+ Private pars() As String = Regex.Split(",", f(i))
+ If pars.Length < 3 Then Log("####################" & CRLF & "Se necesita el id del cliente, la longitud y la latitud" & CRLF & "##############################")
+' Log($"(${i}, ${pars(0)}, 'a', ${pars(2)}, ${pars(1)})"$)
+ db.ExecNonQuery($"insert into ${ruta}_puntos (id, nombre, lat, lon) values ('CC${pars(0)}','a', ${pars(2)}, ${pars(1)})"$)
+ Next
+
+ Private colsMatriz As String = "idT TEXT"
+ Private pp As ResultSet = db.ExecQuery($"select * from ${ruta}_puntos"$)
+ Do While pp.NextRow
+ colsMatriz = $"${colsMatriz},'${pp.GetString("id")}' REAL"$
+ Loop
+' Log(colsMatriz)
+ db.ExecNonQuery($"create table if not exists ${ruta}_matriz (${colsMatriz})"$)
+ db.ExecNonQuery($"create table if not exists ${ruta}_matrizOSRM (${colsMatriz})"$)
+End Sub
+
+Private Sub b_generaMatriz_Click
+' If api = 0 Then
+' generaMatrizLocal("R1")
+' Else
+' generaMatrizOSRM("R1")
+' End If
+End Sub
+
+Sub generaMatrizLocal(ruta As String) 'ignore
+ Log("#################################################################")
+ Log("############# Main/generaMatrizLocal ####################")
+ Log("#################################################################")
+' Log($"delete from ${ruta}_punteo"$)
+ Log("Generamos matriz LOCAL")
+ db.ExecNonQuery($"delete from ${ruta}_punteo"$)
+' Log($"delete from ${ruta}_matriz"$)
+ db.ExecNonQuery($"delete from ${ruta}_matriz"$)
+' matriz = ""
+ punteoLista.Initialize
+' Private otroPunto() As String
+ Private lasCols, losVals As String
+ Private c As ResultSet = db.ExecQuery($"select * from ${ruta}_puntos"$)
+' Dim h As String = c.GetString("id")
+ db.ExecNonQuery($"insert into ${ruta}_punteo (pos, id, nombre, lat, lon) values ('0', '${c.GetString("id")}', 'Almacen', ${c.Getdouble("lat")}, ${c.Getdouble("lon")})"$)
+' Log($"insert into ${ruta}_punteo (pos, id, nombre, lat, lon) values ('0', '${c.GetString("id")}', 'Almacen', ${c.Getdouble("lat")}, ${c.Getdouble("lon")})"$)
+ punteoLista.Add(c.GetString("id")) 'Lista para ruteoNearestInsertion, ponemos el primer punto (almacen).
+ Do While c.NextRow
+ lasCols = "idT"
+' Log($"${c.GetString("id")}, ${c.GetString("nombre")}, ${c.GetString("lat")}, ${c.GetString("lon")}"$)
+ Private d As ResultSet = db.ExecQuery($"select * from ${ruta}_puntos"$)
+ losVals = $"'${c.GetString("id")}'"$
+ Do While d.NextRow
+ Private laDist As Double = calculateDistance1(c.GetDouble("lat"), c.GetDouble("lon"), d.GetDouble("lat"), d.GetDouble("lon"))
+ lasCols = $"${lasCols}, '${d.GetString("id")}'"$
+ losVals = $"${losVals}, '${laDist}'"$
+' Log($"(${c.GetString("id")},${d.GetString("id")}) - Dist entre ${c.GetString("nombre")} y ${d.GetString("nombre")} = ${laDist}"$)
+ Loop
+' Log($"${lasCols}${CRLF}${losVals}"$)
+ db.ExecNonQuery($"insert into ${ruta}_matriz (${lasCols}) values (${losVals})"$)
+ Loop
+ Log("Matriz LOCAL generada")
+' generaMatrizOSRM
+End Sub
+
+Sub generaMatrizOSRM(ruta As String) As ResumableSub 'ignore
+ Log("Generamos matriz OSRM")
+ Log("################################################################")
+ Log("############# Main/generaMatrizOSRM ####################")
+ Log("################################################################")
+ db.ExecNonQuery($"delete from ${ruta}_punteo"$)
+ db.ExecNonQuery($"delete from ${ruta}_matrizOSRM"$)
+' matriz = "OSRM"
+ punteoLista.Initialize
+ Private c As ResultSet = db.ExecQuery($"select * from ${ruta}_puntos"$)
+ db.ExecNonQuery($"insert into ${ruta}_punteo (pos, id, nombre, lat, lon) values ('0', '${c.GetString("id")}', 'Almacen', ${c.Getdouble("lat")}, ${c.Getdouble("lon")})"$)
+ punteoLista.Add(c.GetString("id")) 'Lista para ruteoNearestInsertion, ponemos el primer punto (almacen).
+ Private lasCoords = "", lasCols = "idT", losIds = c.GetString("id") As String 'ignore
+ Private listLasCols As List
+ listLasCols.Initialize
+ Do While c.NextRow
+ listLasCols.Add(c.GetString("Id"))
+ If lasCoords = "" Then
+ lasCoords = $"${c.GetString("lon")},${c.GetString("lat")}"$
+ lasCols = $"${lasCols},'${c.GetString("Id")}'"$
+ Else
+ lasCoords = $"${lasCoords};${c.GetString("lon")},${c.GetString("lat")}"$
+ lasCols = $"${lasCols},'${c.GetString("Id")}'"$
+ End If
+ Loop
+ Log(">>>>>>>>>>>> " & lasCols & CRLF & lasCoords)
+ Dim j As HttpJob
+ j.Initialize("", Me)
+ j.Download($"http://router.project-osrm.org/table/v1/driving/${lasCoords}"$)
+ Wait For (j) JobDone(j As HttpJob)
+ If j.Success Then
+' Log(j.GetString)
+ Private j0 As String = j.GetString
+ End If
+ j.Release
+' StopMessageLoop
+ Private durs As String = j0.SubString2(j0.IndexOf($""durations""$)+12, j0.IndexOf($""sources""$)).Replace("[","")
+ Private dur1() As String = Regex.Split("]", durs)
+ Log(durs)
+ For i = 0 To dur1.Length - 1
+ Private estosVals As String = dur1(i)
+ If estosVals.StartsWith(",") Then estosVals = $"${estosVals.SubString(1)}"$
+ If estosVals.Length > 0 Then
+ estosVals = $"'${listLasCols.get(i)}',${estosVals}"$
+ Log(estosVals)
+' Log($"insert into ${ruta}_matrizOSRM (${lasCols}) values (${estosVals})"$)
+ db.ExecNonQuery($"insert into ${ruta}_matrizOSRM (${lasCols}) values (${estosVals})"$)
+ End If
+ Next
+' fx.ShowExternalDocument($"http://router.project-osrm.org/table/v1/driving/${lasCoords}"$)
+ Log("Matriz OSRM generada")
+End Sub
+
+Sub b_ruteo_Click
+' ruteo("R1")
+End Sub
+
+'Genera el ruteo de la ruta especificada.
+Sub ruteo(ruta As String, matriz As String) 'ignore
+ Log("#####################################################")
+ Log("############# Main/ruteo ####################")
+ Log("#####################################################")
+ db.ExecNonQuery($"delete from ${ruta}_punteo"$)
+ punteoLista.Initialize
+ Private c As ResultSet = db.ExecQuery($"select * from ${ruta}_puntos"$)
+' Dim h As String = c.GetString("id")
+ db.ExecNonQuery($"insert into ${ruta}_punteo (pos, id, nombre, lat, lon) values ('0', '${c.GetString("id")}', 'Almacen', ${c.Getdouble("lat")}, ${c.Getdouble("lon")})"$)
+ punteoLista.Add(c.GetString("id")) 'Lista para ruteoNearestInsertion, ponemos el primer punto (almacen).
+ Private cualAlgoritmo As String = "" 'ignore
+ Log($"Usamos matriz |${matriz}|"$)
+ If algoritmo = 1 Then
+ ruteoNearestInsertion(ruta, matriz)
+ cualAlgoritmo = " (NI)"
+ Else If algoritmo = 0 Then
+ Log(3)
+ ruteoNearestNeighbor(ruta, matriz)
+ cualAlgoritmo = " (NN)"
+ Else
+ ruteoNearestInsertion2
+ cualAlgoritmo = " (NI2)"
+ End If
+End Sub
+
+Private Sub b_verRuta_Click
+' verRuta("R1")
+End Sub
+
+Sub verRuta(ruta As String) 'ignore
+ Log("#######################################################")
+ Log("############# Main/verRuta ####################")
+ Log("#######################################################")
+ Private r As ResultSet = db.ExecQuery($"select * from ${ruta}_punteo"$)
+ Private coords2 As String = ""
+ Do While r.NextRow
+ If coords2 = "" Then
+ coords2 = $"${r.GetString("lon")},${r.GetString("lat")}"$
+ Else
+ coords2 = $"${coords2}:${r.GetString("lon")},${r.GetString("lat")}"$
+ End If
+ Loop
+
+ Log($"http://keymon.lat:9001/kmz.php?a=1&c=${coords2}"$)
+
+' fx.ShowExternalDocument($"https://osm.quelltextlich.at/viewer-js.html?kml_url=https://pi.famguerra.com/kmz.php?c=${coords2}"$)
+' r = db.ExecQuery("select * from ${ruta}_punteo")
+' Private coords2 As String = ""
+' Do While r.NextRow
+' If coords2 = "" Then
+' coords2 = $"${r.GetString("lon")},${r.GetString("lat")}"$
+' Else
+' coords2 = $"${coords2};${r.GetString("lon")},${r.GetString("lat")}"$
+' End If
+' Loop
+' fx.ShowExternalDocument($"http://router.project-osrm.org/route/v1/driving/${coords2}?overview=false"$)
+End Sub
+
+Private Sub b_tiempos_Click
+' tiempos("R1")
+End Sub
+
+'Regresa El tiempo y distancia de la ruta especificada.
+Sub tiempos(ruta As String) As ResumableSub 'ignore
+ Log("#######################################################")
+ Log("############# Main/tiempos ####################")
+ Log("#######################################################")
+' Log("Tiempos: " & ruta)
+ Private c As ResultSet = db.ExecQuery($"select * from ${ruta}_punteo"$)
+ Private estasCoords As String = ""
+ Do While c.NextRow
+ If estasCoords = "" Then
+ estasCoords = $"${c.GetString("lon")},${c.GetString("lat")}"$
+ Else
+ estasCoords = $"${estasCoords};${c.GetString("lon")},${c.GetString("lat")}"$
+ End If
+ Loop
+' fx.ShowExternalDocument($"http://router.project-osrm.org/route/v1/driving/${estasCoords}"$)
+ Private d() As String
+ d = Regex.Split(";", estasCoords)
+' Log("$$$$$$ " & d.Length)
+ Log($"http://router.project-osrm.org/route/v1/driving/${estasCoords}"$)
+ Dim j As HttpJob
+ j.Initialize("", Me)
+ j.Download($"http://router.project-osrm.org/route/v1/driving/${estasCoords}"$)
+ Wait For (j) JobDone(j As HttpJob)
+ If j.Success Then
+ Log("RESPONSE:")
+ Log(j.GetString)
+ Private j0 As String = j.GetString
+ End If
+ j.Release
+' StopMessageLoop
+ Private js As JSONParser
+ js.Initialize(j0)
+' Log(j0)
+' Log("*****************************************")
+' Log(js)
+'' For Each colroot As Map In js
+'' Log(colroot)
+'' Next
+' Log("*****************************************")
+ Private m As Map = js.NextObject
+ Log(m)
+ Private estatus As String = m.Get("code")
+ Private rutas As Map = m.Get("routes").as(List).Get(0)
+ Private waypoints As List = m.Get("waypoints")
+' Log("Response: " & estatus)
+' Log("Duration: " & rutas.Get("duration"))
+' 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))
+' Log(">>>>>>>>>>>>>>>>>>>>>>>>>>>" & ts)
+ Return 1
+End Sub
+
+'Nearest Neighbor
+'The nearest neighbor heuristic Is another greedy algorithm, Or what some may call naive.
+'It starts at one city And connects with the closest unvisited city. It repeats until every city has been visited.
+'It Then returns To the starting city.
+Sub ruteoNearestNeighbor(ruta As String, matriz As String) 'ignore
+ Log("Usamos Nearest Neighbor")
+ Log("####################################################################")
+ Log("############# Main/ruteoNearestNeighbor ####################")
+ Log("####################################################################")
+ Dim g As ResultSet
+ Private x As ResultSet = db.ExecQuery($"select id from ${ruta}_puntos"$)
+ Do While x.NextRow 'Ejecutamos el siguiente codigo la cantidad de veces que hay puntos.
+ Private punto As ResultSet = db.ExecQuery($"select id, count(id) as regs from ${ruta}_punteo order by pos DESC limit 1"$)
+ Do While punto.NextRow
+' Log($"Select idt, '${punto.GetString("id")}', nombre, lat, lon from R1_matriz join R1_puntos on idT = id where idT Not in (Select id from r1_punteo) order by '${punto.GetString("id")}' Asc limit 1"$)
+ g = db.ExecQuery($"Select idt, '${punto.GetString("id")}', nombre, lat, lon from ${ruta}_matriz${matriz} join ${ruta}_puntos on idT = id where idT Not in (Select id from ${ruta}_punteo) order by '${punto.GetString("id")}' Asc limit 1"$)
+ Do While g.NextRow
+ db.ExecNonQuery($"insert into ${ruta}_punteo (pos, id, nombre, lat, lon) values (${punto.GetString("regs")}, '${g.GetString("idT")}', '${g.GetString("nombre")}', '${g.GetString("lat")}', '${g.GetString("lon")}')"$)
+ Loop
+ Loop
+ Loop
+End Sub
+
+'Nearest Insertion
+'The insertion algorithms add new points between existing points on a tour As it grows.
+'One implementation of Nearest Insertion begins with two cities.
+'It then repeatedly finds the city not already in the tour that Is closest to any city in the tour,
+'and places it between whichever two cities would cause the resulting tour to be the shortest possible.
+'It stops when no more insertions remain.
+Sub ruteoNearestInsertion(ruta As String, matriz As String) 'ignore
+ Log($"Usamos Nearest Insertion - Matriz ${matriz}"$)
+ Log("#####################################################################")
+ Log("############# Main/ruteoNearestInsertion ####################")
+ Log("#####################################################################")
+ Private a As ResultSet = db.ExecQuery($"Select idt, ${punteoLista.Get(0)} as laCol, nombre, lat, lon from ${ruta}_matriz${matriz} join ${ruta}_puntos on idT = id where idT <> '${punteoLista.Get(0)}' order by ${punteoLista.Get(0)} asc limit 1"$)
+' Log($"Select idt, ${punteoLista.Get(0)} as laCol, nombre, lat, lon from ${ruta}_matriz${matriz} join ${ruta}_puntos on idT = id where idT <> '${punteoLista.Get(0)}' order by ${punteoLista.Get(0)} asc limit 1"$)
+' Log(punteoLista)
+' Log(a.GetString("idt"))
+ If punteoLista.IndexOf(a.GetString("idt")) = -1 Then
+' Log($"Agregamos ${a.GetString("idt")}"$)
+ punteoLista.Add(a.GetString("idt")) 'Agregamos el punto mas cercano al almacen.
+ End If
+ Private d As ResultSet = db.ExecQuery($"select count(id) as regs from ${ruta}_puntos"$) 'Obtenemos el total de puntos.
+' Log(lis2string(punteoLista))
+ Private b, c, e As ResultSet 'ignore
+' Log(d.GetInt("regs"))
+ For k = 0 To d.GetInt("regs") - 1 'Bucle por el total de puntos en la ruta.
+ Private minimo As Double = 100000000 'Inicializamos con un numero alto para que asigne el primer "minimo" que encuentre.
+ Private elMasCercano = "", elAnterior = "", estePar = "" As String 'ignore
+' Log(punteoLista.Size &"|"&d.GetInt("regs"))
+ Private cuantosPuntos As Int = d.GetInt("regs")
+' cuantosPuntos = 21
+' Log(punteoLista)
+ If punteoLista.Size < cuantosPuntos Then 'Si hay puntos fuera de la ruta ...
+ For j = 0 To punteoLista.Size - 2
+' Log(">>>>>>>>>>>>>>>>>>>>>> ${j} | ${j-2}")
+ 'Buscamos el punto mas cercano (de los que no estan en la lista) a los dos puntos que estamos usando en esta vuelta del bucle.
+ Private b1 As ResultSet = db.ExecQuery($"Select idT, ${punteoLista.Get(j)} as elMinimo from ${ruta}_matriz${matriz} where idT Not in (${lis2string(punteoLista)}) order by ${punteoLista.Get(j)} Asc limit 1"$)
+' Log($"Select idT, ${punteoLista.Get(j)} as elMinimo from ${ruta}_matriz${matriz} where idT Not in (${lis2string(punteoLista)}) order by ${punteoLista.Get(j)} Asc limit 1"$)
+' Log(b1.GetString("elMinimo"))
+ c = db.ExecQuery($"Select idT, "${punteoLista.Get(j+1)}" as elMinimo from ${ruta}_matriz${matriz} where idT Not in (${lis2string(punteoLista)}) order by "${punteoLista.Get(j+1)}" Asc limit 1"$)
+' Log($"Select idT, "${punteoLista.Get(j)}" as elMinimo from ${ruta}_matriz${matriz} where idT Not in (${lis2string(punteoLista)}) order by "${punteoLista.Get(j)}" Asc limit 1"$)
+' Log($"Select idT, "${punteoLista.Get(j+1)}" as elMinimo from ${ruta}_matriz${matriz} where idT Not in (${lis2string(punteoLista)}) order by "${punteoLista.Get(j+1)}" Asc limit 1"$)
+' Log(b1.NextRow)
+ Do While b1.NextRow
+ 'Si b1 regresa registro
+' Log("yyy")
+ If b1.GetDouble("elMinimo") < minimo Or c.GetDouble("elMinimo") < minimo Then
+ minimo = b1.GetDouble("elMinimo")
+ If c.GetDouble("elMinimo") < minimo Then minimo = c.GetDouble("elMinimo")
+ elMasCercano = b1.GetString("idT")
+ elAnterior = punteoLista.Get(j)
+ estePar = $"${punteoLista.Get(j)}|${punteoLista.Get(j+1)}"$
+ End If
+ Loop
+ Next
+ End If
+ If elMasCercano <> "" Then
+' Log($"${elMasCercano}, ${estePar}"$)
+ punteoLista.InsertAt(punteoLista.IndexOf(elAnterior)+1, elMasCercano)
+ End If
+ Next
+' Log(punteoLista)
+ db.ExecNonQuery($"delete from ${ruta}_punteo"$)
+ For h = 0 To punteoLista.Size - 1
+ e = db.ExecQuery($"select * from ${ruta}_puntos where id = '${punteoLista.Get(h)}'"$)
+ Do While e.NextRow
+ db.ExecNonQuery($"insert into ${ruta}_punteo (pos, id, nombre, lat, lon) values (${h}, '${e.GetString("id")}', '${e.GetString("nombre")}', '${e.GetString("lat")}', '${e.GetString("lon")}')"$)
+' Log($"insert into ${ruta}_punteo (pos, id, nombre, lat, lon) values (${h}, '${e.GetString("id")}', '${e.GetString("nombre")}', '${e.GetString("lat")}', '${e.GetString("lon")}')"$)
+ Loop
+ Next
+ Log("Terminamos Nearest Insertion")
+End Sub
+
+'Nearest Insertion
+'The insertion algorithms add new points between existing points on a tour As it grows.
+'One implementation of Nearest Insertion begins with two cities.
+'It then repeatedly finds the city not already in the tour that Is closest to any city in the tour,
+'and places it between whichever two cities would cause the resulting tour to be the shortest possible.
+'It stops when no more insertions remain.
+Sub ruteoNearestInsertion2 'ignore
+' Log("Usamos Nearest Insertion 2")
+'' Log($"Select idt, "${punteoLista.Get(0)}" as laCol, nombre, lat, lon from R1_matriz join R1_puntos on idT = id where idT <> ${punteoLista.Get(0)} order by "${punteoLista.Get(0)}" desc limit 1"$)
+' Private a As ResultSet = db.ExecQuery($"Select idt, "${punteoLista.Get(0)}" as laCol, nombre, lat, lon from R1_matriz${matriz} join R1_puntos on idT = id where idT <> ${punteoLista.Get(0)} order by "${punteoLista.Get(0)}" asc limit 1"$)
+' If punteoLista.IndexOf(a.GetString("idt")) = -1 Then punteoLista.Add(a.GetString("idt")) 'Agregamos el punto mas cercano al almacen.
+' Private d As ResultSet = db.ExecQuery("select count(id) as regs from R1_puntos") 'Obtenemos el total de puntos.
+'' Log(lis2string(punteoLista))
+' Private b, c, e As ResultSet
+'' Log(d.GetInt("regs"))
+' For k = 0 To d.GetInt("regs") - 1 'Bucle por el total de puntos en la ruta.
+' Private minimo As Double = 100000000 'Inicializamos con un numero alto para que asigne el primer "minimo" que encuentre.
+' Private elMasCercano = "", elAnterior = "", estePar = "" As String
+' Log(punteoLista.Size &"|"&d.GetInt("regs"))
+' Private cuantosPuntos As Int = d.GetInt("regs")
+'' cuantosPuntos = 21
+' If punteoLista.Size < cuantosPuntos Then 'Si hay puntos fuera de la ruta ...
+' For j = 0 To punteoLista.Size - 2
+' 'Buscamos el punto mas cercano (de los que no estan en la lista) a los dos puntos que estamos usando en esta vuelta del bucle.
+' b = db.ExecQuery($"Select idT, "${punteoLista.Get(j)}" as elMinimo from R1_matriz${matriz} where idT Not in (${lis2string(punteoLista)}) order by "${punteoLista.Get(j)}" Asc limit 1"$)
+' c = db.ExecQuery($"Select idT, "${punteoLista.Get(j+1)}" as elMinimo from R1_matriz${matriz} where idT Not in (${lis2string(punteoLista)}) order by "${punteoLista.Get(j+1)}" Asc limit 1"$)
+' If b.NextRow Then 'Si b regresa registro
+' If b.GetDouble("elMinimo") < minimo Or c.GetDouble("elMinimo") < minimo Then
+' minimo = b.GetDouble("elMinimo")
+' If c.GetDouble("elMinimo") < minimo Then minimo = c.GetDouble("elMinimo")
+' elMasCercano = b.GetString("idT")
+' elAnterior = punteoLista.Get(j)
+' estePar = $"${punteoLista.Get(j)}|${punteoLista.Get(j+1)}"$
+' End If
+' End If
+' Next
+' End If
+' If elMasCercano <> "" Then
+'' Log($"${elMasCercano}, ${estePar}"$)
+' punteoLista.InsertAt(punteoLista.IndexOf(elAnterior)+1, elMasCercano)
+' End If
+' Next
+' Log(punteoLista)
+' db.ExecNonQuery("delete from R1_punteo")
+' For h = 0 To punteoLista.Size - 1
+' e = db.ExecQuery($"select * from R1_puntos where id = '${punteoLista.Get(h)}'"$)
+' Do While e.NextRow
+' db.ExecNonQuery($"insert into R1_punteo (pos, id, nombre, lat, lon) values (${h}, '${e.GetString("id")}', '${e.GetString("nombre")}', '${e.GetString("lat")}', '${e.GetString("lon")}')"$)
+' Loop
+' Next
+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 calculateDistance2(Latitude1 As Double, Longitude1 As Double, Latitude2 As Double, Longitude2 As Double) As Double 'ignore
+ Dim EarthRadius, Angle, distance As Double
+ EarthRadius = 6378.137 ' WGS -84 kilometers?
+ Angle = ACos(SinD(Latitude1) * SinD(Latitude2) + CosD(Latitude1) * CosD(Latitude2) * CosD(Longitude2 - Longitude1))
+ distance = EarthRadius * Angle
+ Return distance * 1000
+End Sub
+
+Public Sub calculateDistance3(lat1 As Double, lon1 As Double, lat2 As Double, lon2 As Double) As Double 'ignore
+ Try
+ Dim Miles As Double
+ Dim Yards As Double
+ Dim X As Double
+ Dim Coeff As Double= 1760.0
+ X = Sin(lat1 * 0.01745) * Sin(lat2 * 0.01745) + Cos(lat1 * 0.01745)* Cos(lat2 * 0.01745) * Cos(( lon2 - lon1 ) * 0.01745)
+ Miles = 1.15 * 3963 * ( ATan(-X / Sqrt(-X * X+ 1.0000000000001)) + 2* ATan(1) )
+' Miles = Round2(Miles, 2)
+ Yards = Miles * Coeff
+ Return Round(Yards)
+ Catch
+ Log("CalcDistance " & LastException)
+ Return -1
+ End Try
+End Sub
+
+Sub lis2string(l As List) As String 'ignore
+ Private s As String = ""
+ For i = 0 To l.Size - 1
+ If s = "" Then
+ s = $"'${l.get(i)}'"$
+ Else
+ s = $"${s}, '${l.get(i)}'"$
+ End If
+ Next
+ Return s
+End Sub
+
+Private Sub cb_algorithm_SelectedIndexChanged(Index As Int, Value As Object)
+'' Log(Index)
+' algoritmo = Index
+End Sub
+
+Private Sub cb_api_SelectedIndexChanged(Index As Int, Value As Object)
+' api = Index
+' If Index = 0 Then matriz = "" Else matriz = "OSRM"
+End Sub
\ No newline at end of file
diff --git a/Ruteador-NonUI.b4j.meta b/Ruteador-NonUI.b4j.meta
new file mode 100644
index 0000000..4449f42
--- /dev/null
+++ b/Ruteador-NonUI.b4j.meta
@@ -0,0 +1,21 @@
+ModuleBookmarks0=
+ModuleBookmarks1=
+ModuleBookmarks2=
+ModuleBookmarks3=
+ModuleBookmarks4=
+ModuleBookmarks5=
+ModuleBreakpoints0=
+ModuleBreakpoints1=
+ModuleBreakpoints2=
+ModuleBreakpoints3=
+ModuleBreakpoints4=
+ModuleBreakpoints5=
+ModuleClosedNodes0=
+ModuleClosedNodes1=
+ModuleClosedNodes2=
+ModuleClosedNodes3=
+ModuleClosedNodes4=
+ModuleClosedNodes5=
+NavigationStack=delDB,Class_Globals,7,0,Main,b_tiempos_Click,302,0,Main,ruteoNearestInsertion,387,0,Main,AppStart,22,0,Ruteador,generaMatrizRuteoTiempos,86,4,Mapa,ruteoCompleto,152,6,rutaCompleta,ruteoCompleto,153,0,Ruteador,tiempos,125,6,delDB,Handle,31,6,Main,tiempos,331,6,Main,Process_Globals,18,0
+SelectedBuild=0
+VisibleModules=5,3,4,1,2
diff --git a/Ruteador.bas b/Ruteador.bas
new file mode 100644
index 0000000..9c5f2bc
--- /dev/null
+++ b/Ruteador.bas
@@ -0,0 +1,179 @@
+B4J=true
+Group=Default Group
+ModulesStructureVersion=1
+Type=Class
+Version=10
+@EndOfDesignText@
+'Class module
+Sub Class_Globals
+ Private mreq As ServletRequest 'ignore
+ Private mresp As ServletResponse 'ignore
+' Dim cmd As DBCommand
+ Dim theQuery As String
+ Dim m, m2 As Map
+ Dim getHash As CalculateHash
+ Dim js As JSONGenerator
+End Sub
+
+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("############# Ruteador/Handle ########################")
+ Log("##############################################################")
+' Log("q='"&req.GetParameter("q")&"'")
+ Log($"REQ: ${req.FullRequestURI}"$)
+ Private elHash As String = 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")
+ 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
+ ruta = "R" & ruta
+ urlParams.Initialize
+ urlParams.Put("almacen", almacen)
+ urlParams.Put("coords", coords)
+ urlParams.Put("hash", elHash)
+ urlParams.Put("ruta", ruta)
+ Main.db.InitializeSQLite(File.DirApp, "kmt.db", True)
+ Log($"${ruta}A${almacen}_${elHash}_punteo"$)
+' Log(checkIfTableExists($"${ruta}A${almacen}_${elHash}_punteo"$))
+
+' Si no existe la tabla del ruteo, la creamos.
+ If Not(checkIfTableExists($"${ruta}A${almacen}_${elHash}_punteo"$)) Then
+' Log($"Creamos tablas ruta ${ruta}, almacen ${almacen}"$)
+ Main.creaTablas(urlParams)
+ generaMatrizRuteoTiempos($"${ruta}A${almacen}_${elHash}"$, resp, ruta, almacen, matriz)
+ StartMessageLoop
+ Else 'Si ya existe, solo calculamos los tiempos y distancias.
+' Log("Ya existe la tabla")
+ tiempos($"${ruta}A${almacen}_${elHash}"$, resp, ruta, almacen, matriz)
+ StartMessageLoop
+' Main.verRuta(ruta)
+ End If
+ Else
+ resp.ContentType = "text/html"
+ resp.Write("Hay un error en la solicitud, son necesarios los parametros:
* r - La ruta
* a - El almacen
* c - id_cliente,lon,lat separadas por punto y coma.
* m - La matriz a usar LOCAL u OSRM (Opcional, default local)") 'this file will be loaded from the www folder
+ End If
+End Sub
+
+Sub generaMatrizRuteoTiempos(r As String, resp As ServletResponse, ruta As String, almacen As String, matriz As String) As ResumableSub
+ Log("############################################################################")
+ Log("############# Ruteador/generaMatrizRuteoTiempos ####################")
+ Log("############################################################################")
+ 'Generamos la matriz
+ If matriz = "OSRM" Then
+ Wait for(Main.generaMatrizOSRM(r)) Complete (Result As Int)
+ Else
+ Main.generaMatrizLocal(r)
+ End If
+ 'Generamos el ruteo
+ Main.ruteo($"${r}"$, matriz)
+ Wait for(Main.tiempos($"${r}"$)) Complete (Result As Int)
+ Private ts As Map = Main.ts.Get($"${r}"$)
+ Log(ts)
+ Private tempMap As Map
+ tempMap.Initialize
+ Private p As ResultSet = Main.db.ExecQuery($"select * from ${r}_punteo"$)
+ Private listCoords As List
+ listCoords.Initialize
+ 'Ponemos el id de la tienda y las coordenadas en una lista para regresarla en un JSON.
+ Do While p.NextRow
+ listCoords.Add(CreateMap("pos":p.GetString("pos"), "id":p.GetString("id"), "lat":p.GetString("lat"), "lon":p.GetString("lon")))
+ Loop
+ Main.db.Close
+ tempMap.Put("api", matriz)
+ 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("ruta", ruta)
+ tempMap.Put("almacen", almacen)
+ tempMap.Put("duration", ts.Get("duration"))
+ tempMap.Put("distance", ts.Get("distance"))
+ tempMap.Put("puntos", ts.Get("puntos"))
+ tempMap.Put("coords", listCoords)
+' Log(tempMap)
+ js.Initialize(tempMap)
+ StopMessageLoop
+ 'Regresamos en un JSON la info del ruteo.
+ resp.ContentType = "text/html"
+ resp.Write(js.ToString)
+ Return 1
+End Sub
+
+Sub tiempos(r As String, resp As ServletResponse, ruta As String, almacen As String, matriz As String) As ResumableSub
+ Log("############################################################")
+ Log("############# Ruteador/tiempos ####################")
+ Log("############################################################")
+ Wait for(Main.tiempos($"${r}"$)) Complete (Result As Int)
+ Private ts As Map = Main.ts.Get($"${r}"$)
+ Log(ts)
+ Private tempMap As Map
+ tempMap.Initialize
+ Private p As ResultSet = Main.db.ExecQuery($"select * from ${r}_punteo"$)
+ Private listCoords As List
+ listCoords.Initialize
+ Private coords2 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")}"$
+ Else
+ coords2 = $"${coords2}:${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("ruta", ruta)
+ tempMap.Put("almacen", almacen)
+ tempMap.Put("duration", ts.Get("duration"))
+ tempMap.Put("distance", ts.Get("distance"))
+ tempMap.Put("puntos", ts.Get("puntos"))
+ tempMap.Put("coords", listCoords)
+' Log(tempMap)
+ js.Initialize(tempMap)
+ StopMessageLoop
+ resp.ContentType = "text/html"
+ resp.Write(js.ToString)
+ Log("###################################################################" & CRLF)
+ Log($"http://keymon.lat:9001/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}"$)
+ Return 1
+End Sub
+
+'Convierte una lista en un arreglo (array as object).
+Public Sub ListToArray(inList As List) As Object()
+ Dim OutArray(inList.Size) As Object
+ For i = 0 To inList.Size - 1
+ OutArray(i) = inList.Get(i)
+ Next
+ Return OutArray
+End Sub
+
+Sub checkIfTableExists(table As String) As Boolean
+' B4XPages.MainPage.db.InitializeSQLite(File.DirApp, "kmt.db", True)
+ Private r As ResultSet = Main.db.ExecQuery($"Select name FROM sqlite_master WHERE Type='table' AND name='${table}'"$)
+ If r.NextRow Then
+' B4XPages.MainPage.db.close
+' Log($"NAME: ${r.GetString("name")}"$)
+ Return True
+ Else
+' B4XPages.MainPage.db.close
+ Return False
+ End If
+End Sub
\ No newline at end of file
diff --git a/WSGuessMyNumber.bas b/WSGuessMyNumber.bas
new file mode 100644
index 0000000..25c70c4
--- /dev/null
+++ b/WSGuessMyNumber.bas
@@ -0,0 +1,65 @@
+B4J=true
+Group=Default Group
+ModulesStructureVersion=1
+Type=Class
+Version=2.18
+@EndOfDesignText@
+'Class module
+Sub Class_Globals
+ Private ws As WebSocket
+ Private myNumber As Int
+ Private timer1 As Timer
+ 'these variables will be set automatically.
+ Private TxtNumber As JQueryElement 'matches an element with id = "txtnumber"
+ Private Result As JQueryElement
+ Private ServerTime As JQueryElement
+End Sub
+
+Public Sub Initialize
+ myNumber = Rnd(1, 101)
+End Sub
+
+Private Sub WebSocket_Connected (WebSocket1 As WebSocket)
+ ws = WebSocket1
+ timer1.Initialize("timer1", 1000)
+ timer1.Enabled = True
+End Sub
+
+Private Sub WebSocket_Disconnected
+ timer1.Enabled = False
+End Sub
+
+Sub btnGuess_Click (Params As Map)
+ Log(ws.Secure)
+ Dim s As Long = DateTime.Now
+ Dim number As String = TxtNumber.GetVal.Value
+ If IsNumber(number) Then
+ Dim n As Int = number
+ If n > myNumber Then
+ Result.SetHtml("My number is smaller.")
+ Else If n < myNumber Then
+ Result.SetHtml("My number is larger.")
+ Else
+ Result.SetHtml("Well done!!!")
+ End If
+ Else
+ Result.SetHtml("Please enter a valid number.")
+ End If
+ TxtNumber.RunMethod("select", Null)
+ Log(ws.UpgradeRequest.RemoteAddress & ": " & (DateTime.Now - s))
+End Sub
+
+Sub Timer1_Tick
+ ServerTime.SetHtml("Server time: " & DateTime.Time(DateTime.Now))
+ ws.Flush 'required here as this is a server event
+End Sub
+
+Sub txtNumber_KeyUp(Params As Map)
+ If 13 = Params.Get("which") Then
+ btnGuess_Click (Null)
+ End If
+End Sub
+
+Sub btnReset_Click (Params As Map)
+ myNumber = Rnd(1, 101)
+End Sub
diff --git a/delDB.bas b/delDB.bas
new file mode 100644
index 0000000..1773db6
--- /dev/null
+++ b/delDB.bas
@@ -0,0 +1,57 @@
+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
+' Dim cmd As DBCommand
+ Dim theQuery As String
+ Dim m, m2 As Map
+ Dim getHash As CalculateHash
+ Dim js As JSONGenerator
+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("q='"&req.GetParameter("q")&"'")
+ Log($"REQ: ${req.FullRequestURI}"$)
+ Private b As String = req.GetParameter("b")
+ If b = 1 Then
+ Try
+ Log("Borramos base")
+ Main.db.InitializeSQLite(File.DirApp, "kmt.db", True)
+
+ Main.db.ExecNonQuery("PRAGMA writable_schema = 1")
+ Main.db.ExecNonQuery("delete from sqlite_master where Type in ('table', 'index', 'trigger')")
+ Main.db.ExecNonQuery("PRAGMA writable_schema = 0")
+
+' Private t As ResultSet = Main.db.ExecQuery($"Select name FROM sqlite_master WHERE Type='table'"$)
+' Do While t.NextRow
+' Log(t.GetString("name"))
+' Main.db.ExecNonQuery($"drop table ${t.GetString("name")}"$)
+' Loop
+ Main.db.ExecNonQuery("vacuum")
+
+ Catch
+ Log(LastException)
+ End Try
+ Else
+ resp.ContentType = "text/html"
+ resp.Write("Hay un error en la solicitud, son necesarios los parametros:
* r - La ruta
* a - El almacen
* c - id_cliente,lon,lat separadas por punto y coma.
* m - La matriz a usar LOCAL u OSRM (Opcional, default local)") 'this file will be loaded from the www folder
+ End If
+End Sub
+
+
+
diff --git a/rutaCompleta.bas b/rutaCompleta.bas
new file mode 100644
index 0000000..8def770
--- /dev/null
+++ b/rutaCompleta.bas
@@ -0,0 +1,197 @@
+B4J=true
+Group=Default Group
+ModulesStructureVersion=1
+Type=Class
+Version=10
+@EndOfDesignText@
+'Class module
+Sub Class_Globals
+ Private mreq As ServletRequest 'ignore
+ Private mresp As ServletResponse 'ignore
+' Dim cmd As DBCommand
+ Dim getHash As CalculateHash
+ Dim js As JSONGenerator
+End Sub
+
+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("############# rutaCompleta/Handle ################")
+ Log("##########################################################")
+' Log("q='"&req.GetParameter("q")&"'")
+' Log($"REQ: ${req.FullRequestURI}"$)
+ Private elHash As String = 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")
+ 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
+ ruta = "R" & ruta
+ urlParams.Initialize
+ urlParams.Put("almacen", almacen)
+ urlParams.Put("coords", coords)
+ urlParams.Put("hash", elHash)
+ urlParams.Put("ruta", ruta)
+ Main.db.InitializeSQLite(File.DirApp, "kmt.db", True)
+
+' Si no existe la tabla del ruteo, la creamos.
+ If Not(checkIfTableExists($"${ruta}A${almacen}_${elHash}_punteo"$)) Then
+ Log($"Creamos tablas ruta ${ruta}, almacen ${almacen}"$)
+ Main.creaTablas(urlParams)
+ generaMatrizRuteoTiempos($"${ruta}A${almacen}_${elHash}"$, resp, ruta, almacen, matriz)
+ StartMessageLoop
+ Else 'Si ya existe, solo calculamos los tiempos y distancias.
+' tiempos($"${ruta}A${almacen}_${elHash}"$, resp, ruta, almacen, matriz)
+ ruteoCompleto($"${ruta}A${almacen}_${elHash}"$)
+ StartMessageLoop
+ End If
+ Else
+ resp.ContentType = "text/html"
+ resp.Write("Hay un error en la solicitud, son necesarios los parametros:
* r - La ruta
* a - El almacen
* c - id_cliente,lon,lat separadas por punto y coma.
* m - La matriz a usar LOCAL u OSRM (Opcional, default local)") 'this file will be loaded from the www folder
+ End If
+End Sub
+
+Sub generaMatrizRuteoTiempos(r As String, resp As ServletResponse, ruta As String, almacen As String, matriz As String) As ResumableSub
+ Log("############################################################################")
+ Log("############# rutaCompleta/generaMatrizRuteoTiempos ################")
+ Log("############################################################################")
+ 'Generamos la matriz
+ If matriz = "OSRM" Then
+ Wait for(Main.generaMatrizOSRM(r)) Complete (Result As Int)
+ Else
+ Main.generaMatrizLocal(r)
+ End If
+ 'Generamos el ruteo
+ Main.ruteo($"${r}"$, matriz)
+' Wait for(Main.tiempos($"${r}"$)) Complete (Result As Int)
+' Private ts As Map = Main.ts.Get($"${r}"$)
+' Log(ts)
+ Private p As ResultSet = Main.db.ExecQuery($"select * from ${r}_punteo"$)
+ Private listCoords As String = ""
+ 'Ponemos el id de la tienda y las coordenadas en una lista para regresarla en un JSON.
+ Do While p.NextRow
+ If listCoords = "" Then
+ listCoords = $"${p.GetString("lon")},${p.GetString("lat")}"$
+ Else
+ listCoords = $"${listCoords}:${p.GetString("lon")},${p.GetString("lat")}"$
+ End If
+ Loop
+ Main.db.Close
+ StopMessageLoop
+ resp.ContentType = "text/html"
+
+ resp.Write($"Mapa"$)
+ Return 1
+End Sub
+
+Sub tiempos(r As String, resp As ServletResponse, ruta As String, almacen As String, matriz As String) As ResumableSub
+ Log("###########################################################")
+ Log("############# rutaCompleta/tiempos ################")
+ Log("###########################################################")
+ Private p As ResultSet = Main.db.ExecQuery($"select * from ${r}_punteo"$)
+ Private listCoords As String = ""
+ Do While p.NextRow
+ If listCoords = "" Then
+ listCoords = $"${p.GetString("lon")},${p.GetString("lat")}"$
+ Else
+ listCoords = $"${listCoords}:${p.GetString("lon")},${p.GetString("lat")}"$
+ End If
+ Loop
+ Main.db.Close
+
+' Log("Iniciamos ruteoCompleto")
+' ruteoCompleto(r)
+
+ StopMessageLoop
+ resp.ContentType = "text/html"
+ resp.Write($"Mapa"$)
+ Return 1
+End Sub
+
+
+'Regresa la ruta esquina a esquina.
+Sub ruteoCompleto(ruta As String) As ResumableSub 'ignore
+ Log("#################################################################")
+ Log("############# rutaCompleta/ruteoCompleto ################")
+ Log("#################################################################")
+' Log("Tiempos: " & ruta)
+ Private c As ResultSet = Main.db.ExecQuery($"select * from ${ruta}_punteo"$)
+ Private estasCoords As String = ""
+ Private ts As Map
+ ts.Initialize
+ Do While c.NextRow
+ If estasCoords = "" Then
+ estasCoords = $"${c.GetString("lon")},${c.GetString("lat")}"$
+ Else
+ estasCoords = $"${estasCoords};${c.GetString("lon")},${c.GetString("lat")}"$
+ End If
+ Loop
+ Dim j As HttpJob
+ j.Initialize("", Me)
+ j.Download($"http://router.project-osrm.org/route/v1/driving/${estasCoords}?steps=true"$)
+ Wait For (j) JobDone(j As HttpJob)
+ If j.Success Then
+' Log(j.GetString)
+ Private j0 As String = j.GetString
+ End If
+ j.Release
+' StopMessageLoop
+ Private js1 As JSONParser
+ js1.Initialize(j0)
+' Log(js1)
+' For Each colroot As Map In js
+' Log(colroot)
+' Next
+' Log("*****************************************")
+' Log(js.NextObject)
+ Private m As Map = js1.NextObject
+' Private estatus As String = m.Get("code")
+ Private rutas As Map = m.Get("routes").as(List).Get(0)
+' Private waypoints As List = m.Get("waypoints")
+' Log("Response: " & estatus)
+' Log("Duration: " & rutas.Get("duration"))
+' Log("Distance: " & rutas.Get("distance"))
+' Log("Legs: " & rutas.Get("legs").As(List).Size)
+' Log("Waypoints: " & waypoints.Size)
+ Private steps As List
+ steps.Initialize
+ steps = rutas.Get("legs").as(List).get(0).As(Map).Get("steps")
+ Log("STEPS SIZE: " & steps.Size)
+ ts.Put(ruta, CreateMap("code":"Ok", "duration":rutas.Get("duration"), "distance":rutas.Get("distance"), "puntos":rutas.Get("legs").As(List).Size))
+' Log(">>>>>>>>>>>>>>>>>>>>>>>>>>>" & ts)
+ Return 1
+End Sub
+
+'Convierte una lista en un arreglo (array as object).
+Public Sub ListToArray(inList As List) As Object()
+ Dim OutArray(inList.Size) As Object
+ For i = 0 To inList.Size - 1
+ OutArray(i) = inList.Get(i)
+ Next
+ Return OutArray
+End Sub
+
+Sub checkIfTableExists(table As String) As Boolean
+' B4XPages.MainPage.db.InitializeSQLite(File.DirApp, "kmt.db", True)
+ Private r As ResultSet = Main.db.ExecQuery($"Select name FROM sqlite_master WHERE Type='table' AND name='${table}'"$)
+ If r.NextRow Then
+' B4XPages.MainPage.db.close
+' Log($"NAME: ${r.GetString("name")}"$)
+ Return True
+ Else
+' B4XPages.MainPage.db.close
+ Return False
+ End If
+End Sub
\ No newline at end of file