Code archives/Algorithms/3D Short est Path
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
| I am not sure if this has been discussed before but I implemented the Dijkstra's algorithm trying to solve the Single-pair shortest-path problem in a 3D graph. 1. First you must create a graph using the following command: mygraph = Graph_Create(0) Where 0 is the graph id (you can create many graphs using different id's) 2. Build the graph by adding vertices: v1.Vertex = Graph_CreateVertex(mygraph, x1, y1, z1) v2.Vertex = Graph_CreateVertex(mygraph, x2, y2, z2) ... 3. Create connections between vertices use: Vertex_Connection(v1, v2) ... 4. Make a function call: Graph_FindShortestPath(mygraph, src, dest) where src and dest are existing vertices within mygraph Each graph has the bestsearch vertex and after the previous call you can trace the shortest path following the predecessor member of the bestsearch vertex The most interesting is that you can define your own 'cost' between two vertices by modifying the Vertex_GetCost() function in the way you like. Currently in the program the 'cost' between two vertices is their distance If you are confused check the source. If you build a graph and you find that the program does not calculate the shortest path please let me now in order to debug it. Enjoy! | |||||
Const MAXCONPERVER%=20 ; Max connections per vertex
Type Vertex
Field d# ; shortest path estimation. A value of d = -1 represents infinity
Field p.Vertex ; predecessor (used in Dijkstra's algorithm)
Field m% ; visual representation of vertex
Field graphid% ; Graph id where vertex belongs. If graphid = -1 then it not belongs to any graph
Field connection.Vertex[MAXCONPERVER] ; array of connected vertices.
Field conidx% ; index to connection matrix. Range: From 0 to MAXCONPERVER-1
End Type
Type Graph
Field id% ; graph id
Field visible%
Field vcount% ; vertices counter
Field bestreach.Vertex
End Type
Graphics3D 800, 600, 32
Global l% = CreateLight() : RotateEntity l,0,90,0
Global cam% = CreateCamera() : MoveEntity cam, 0,10,-20
Global camerapivot% = CreatePivot() :EntityParent cam, camerapivot
Global fntArial = LoadFont("Arial",15) : SetFont fntArial
Global done% = False
Global g_source.Vertex=Null
Global g_dest.Vertex=Null
Global Graph1.Graph = Graph_Create(0)
Global v1.Vertex = Graph_CreateVertex(Graph1, 0, 0, 0)
Global v2.Vertex = Graph_CreateVertex(Graph1, 5, 0, 5)
Global v3.Vertex = Graph_CreateVertex(Graph1, 0, 20, 5)
Global v4.Vertex = Graph_CreateVertex(Graph1, -5, 0, 5)
Global v5.Vertex = Graph_CreateVertex(Graph1, 5, 5, 10)
Global v6.Vertex = Graph_CreateVertex(Graph1, 2, 4, 10)
Global v7.Vertex = Graph_CreateVertex(Graph1, -5, 6,8)
Global v8.Vertex = Graph_CreateVertex(Graph1, 0, 0, 15)
Vertex_Connection(v1, v2)
Vertex_Connection(v1, v3)
Vertex_Connection(v1, v4)
Vertex_Connection(v2, v4)
Vertex_Connection(v3, v6)
Vertex_Connection(v4, v7)
Vertex_Connection(v4, v6)
Vertex_Connection(v6, v8)
Vertex_Connection(v7, v8)
Graph_SetVisible(Graph1, True)
Repeat
CaptureWorld
UpdateWorld
RenderWorld
Graph_DrawConnections(Graph1, cam)
Info()
Flip
CameraDrive(cam, camerapivot)
If KeyHit(1) Then done = True
If KeyHit(34) Then Graph_SetVisible(Graph1, Not Graph1\visible)
If KeyHit(32)
If g_source<>Null And g_dest<>Null
Graph_SetNodeColor(Graph1, 255, 255, 255)
Graph_FindShortestPath(Graph1, g_source, g_dest)
v.Vertex = Graph1\bestreach
While v<>Null
EntityColor v\m, 255,255,0
v = v\p
Wend
If g_source<>Null Then EntityColor g_source\m, 0,255,0
If g_dest<>Null Then EntityColor g_dest\m, 255,0,0
EndIf
EndIf
Until done
Graph_Delete(Graph1)
End
;******************
;
; UTILITY FUNCTIONS
;
;******************
Function Info()
y = 0
Text 0,y,"Camera navigation"
y = y + FontHeight()
Text 0,y,"LMB: Move"
y = y + FontHeight()
Text 0,y,"RMB: Rotate"
y = y + FontHeight()
Text 0,y,"[ALT]+LMB: Up/Down"
y = y + FontHeight()
Text 0,y,"LMB+RMB: Pitch"
y = y + 2*FontHeight()
Text 0,y,"Commands"
y = y + FontHeight()
Text 0,y,"LMB: Select source node"
y = y + FontHeight()
Text 0,y,"RMB: Select destination node"
y = y + FontHeight()
Text 0,y,"[D]: Run Dijkstra's algorithm"
y = y + FontHeight()
Text 0,y,"[G]: Toggle graph visibility"
End Function
Function CameraDrive(c%, cp%)
If MouseHit(1)
m% =CameraPick(c, MouseX(), MouseY())
For v.Vertex = Each Vertex
If m = v\m
If g_source<>Null Then EntityColor g_source\m, 255,255,255
g_source = v
EntityColor g_source\m, 0,255,0
EndIf
Next
EndIf
If MouseHit(2)
m% =CameraPick(c, MouseX(), MouseY())
For v.Vertex = Each Vertex
If m = v\m
If g_dest<>Null Then EntityColor g_dest\m, 255,255,255
g_dest = v
EntityColor g_dest\m, 255,0,0
EndIf
Next
EndIf
If MouseDown(1) And MouseDown(2)=0 And KeyDown(56) = 0
MoveEntity c, -MouseXSpeed(),0,0
MoveEntity c, 0,0,MouseYSpeed()
EndIf
If MouseDown(1)=0 And MouseDown(2) Then TurnEntity cp, 0,Sgn(MouseXSpeed())*5,0
If MouseDown(1) And MouseDown(2) Then TurnEntity c,MouseYSpeed(),0,0
If KeyDown(56)=1 And MouseDown(1) Then MoveEntity c, 0,MouseYSpeed(),0
MouseXSpeed()
MouseYSpeed()
MouseZSpeed()
End Function
;*****************
;
; VERTEX FUNCTIONS
;
;*****************
Function Vertex_Create.Vertex(x#, y#, z#)
v.Vertex = New Vertex
v\d = -1
v\p = Null
v\m = CreateSphere() : PositionEntity v\m, x,y,z : EntityPickMode v\m,2
v\graphid = -1
v\conidx = 0
For i%=1 To MAXCONPERVER
v\connection[i] = Null
Next
Return v
End Function
Function Vertex_Copy.Vertex(src.Vertex)
If src = Null Then Return
dest.Vertex = New Vertex
dest\d = src\d
dest\p = src\p
dest\m = CreateSphere() : PositionEntity dest\m, EntityX(src\m),EntityY(src\m),EntityZ(src\m)
dest\graphid = src\graphid
dest\conidx = src\conidx
For i%=o To dest\conidx
dest\connection[i] = src\connection[i]
Next
Return dest
End Function
Function Vertex_Delete(v.Vertex)
If v = Null Then Return
FreeEntity v\m
Delete v
v = Null
End Function
Function Vertex_Connection(src.Vertex, dest.Vertex)
If src = Null Or dest = Null Then Return
If src\conidx = MAXCONPERVER-1 Then Return ; we reched maximum number of connections in source
If dest\conidx = MAXCONPERVER-1 Then Return ; we reched maximum number of connections in dest
src\connection[src\conidx] = dest
src\conidx = src\conidx + 1
dest\connection[dest\conidx] = src
dest\conidx = dest\conidx + 1
End Function
Function Vertex_RemoveConnection(v.Vertex, src.Vertex)
Local i%, j%, n%, doremove%=False
If v = Null Or n > v\conidx-1 Or v\conidx=0 Then Return
For i=0 To v\conidx-1
If v\connection[i] = src
n = i
doremove = True
Exit
EndIf
Next
If Not doremove Then Return
For i=0 To v\conidx
If i=n
For j=i+1 To v\conidx-1
v\connection[j-1] = v\connection[j]
Next
EndIf
Next
v\conidx = v\conidx - 1
End Function
Function Vertex_DrawConnections(v.Vertex, c%, r%=255, g%=255, b%=255)
Local x1#, y1#, z1#
If Not EntityInView(v\m, c) Then Return
CameraProject c, EntityX(v\m), EntityY(v\m), EntityZ(v\m)
x1 = ProjectedX()
y1 = ProjectedY()
z1 = ProjectedZ()
Color r, g, b
For i=0 To v\conidx-1
If EntityInView(v\m, c)
CameraProject c, EntityX(v\connection[i]\m), EntityY(v\connection[i]\m), EntityZ(v\connection[i]\m)
Line x1, y1, ProjectedX(), ProjectedY()
EndIf
Next
End Function
;
; returns the distance between v and its neigbor specified by n index
; If v does not exist or n index is invalid then returns infinite (-1)
;
Function Vertex_GetCost#(v.Vertex, n%)
If v = Null Then Return -1
If n<0 Or n>v\conidx-1 Then Return -1
Return EntityDistance(v\m, v\connection[n]\m)
End Function
;*****************
;
; GRAPH FUNCTIONS
;
;*****************
Function Graph_Create.Graph(id%)
gr.Graph = New Graph
If gr = Null Then Return
gr\id = id
gr\visible = False
gr\vcount = 0
gr\bestreach = Null
Return gr
End Function
Function Graph_Copy.Graph(src.Graph, id%)
Local doconnect%
If src = Null Then Return Null
dest.Graph = New Graph
If dest = Null Then Return Null
dest\id = id
dest\bestreach = src\bestreach
; create new vertices and add into the destination graph
For v.Vertex = Each Vertex
If v\graphid = src\id
newv.Vertex = Vertex_Create(EntityX(v\m), EntityY(v\m), EntityZ(v\m))
newv\d = v\d
Graph_AddVertex(dest, newv)
EndIf
Next
; create connections in the destination graph
For v.Vertex = Each Vertex
If v\graphid = src\id
v1.Vertex = Graph_FindVertex(dest, EntityX(v\m), EntityY(v\m), EntityZ(v\m))
For i%=0 To v\conidx-1
v2.Vertex = Graph_FindVertex(dest, EntityX(v\connection[i]\m), EntityY(v\connection[i]\m), EntityZ(v\connection[i]\m))
; do not duplicate the same connection
doconnect = True
For j%=0 To v2\conidx-1
If v2\connection[j] = v1 Then doconnect = False
Next
If doconnect Then Vertex_Connection(v1, v2)
Next
EndIf
Next
Graph_SetVisible(dest, src\visible)
Return dest
End Function
Function Graph_Delete(gr.Graph)
If gr = Null Then Return
Graph_DeleteAllVertices(gr)
Delete gr
gr = Null
End Function
Function Graph_Move(gr.Graph, dx#, dy#, dz#)
If gr = Null Then Return
For v.Vertex = Each Vertex
If v\graphid = gr\id
MoveEntity v\m, dx, dy, dz
EndIf
Next
End Function
Function Graph_CreateVertex.Vertex(gr.Graph, x#, y#, z#)
If gr = Null Then Return
v.Vertex = Vertex_Create(x, y, z)
v\graphid = gr\id
HideEntity v\m
gr\vcount = gr\vcount + 1
Return v
End Function
Function Graph_AddVertex(gr.Graph, v.Vertex)
If gr = Null Or v = Null Then Return
v\graphid = gr\id
If gr\visible
ShowEntity v\m
Else
HideEntity v\m
EndIf
gr\vcount = gr\vcount + 1
End Function
Function Graph_RemoveVertexShallow.Vertex(gr.Graph, v.Vertex)
If gr = Null Or v = Null Or gr\vcount = 0 Then Return Null
v\graphid = -1
gr\vcount = gr\vcount - 1
Return v
End Function
Function Graph_RemoveVertexDeep.Vertex(gr.Graph, v.Vertex)
If gr = Null Or v = Null Or gr\vcount = 0 Then Return Null
v\graphid = -1
gr\vcount = gr\vcount - 1
; remove connections of vertex v from graph
For vv.Vertex = Each Vertex
If vv\graphid = gr\id
Vertex_RemoveConnection(vv, v)
EndIf
Next
Return v
End Function
Function Graph_DeleteAllVertices(gr.Graph)
If gr = Null Then Return
For v.Vertex = Each Vertex
If v\graphid = gr\id
Vertex_Delete(v)
EndIf
Next
gr\vcount = 0
End Function
Function Graph_FindVertex.Vertex(gr.Graph, x#, y#, z#)
For v.Vertex = Each Vertex
If v\graphid = gr\id
If (x=EntityX(v\m) And y=EntityY(v\m) And z=EntityZ(v\m)) Return v
EndIf
Next
Return Null
End Function
Function Graph_SetNodeColor(gr.Graph, r%, g%, b%)
If gr = Null Then Return
For v.Vertex = Each Vertex
If v\graphid = gr\id
EntityColor v\m, r, g, b
EndIf
Next
End Function
Function Graph_SetVisible(gr.Graph, visible%=True)
If gr\visible = visible Then Return
gr\visible = visible
For v.Vertex = Each Vertex
If v\graphid = gr\id
If gr\visible
ShowEntity v\m
Else
HideEntity v\m
EndIf
EndIf
Next
End Function
Function Graph_DrawConnections(gr.Graph, c%, r%=255, g%=255, b%=255)
If gr = Null Then Return
If gr\visible = False Then Return
For v.Vertex = Each Vertex
If v\graphid = gr\id Then Vertex_DrawConnections(v, c)
Next
End Function
Function Graph_DrawDistances(gr.Graph, c%, r%=255, g%=255, b%=255)
If gr = Null Then Return
If gr\visible = False Then Return
Color r, g, b
For v.Vertex = Each Vertex
If v\graphid = gr\id
If EntityInView(v\m, c)
CameraProject(c, EntityX(v\m), EntityY(v\m), EntityZ(v\m))
Text ProjectedX(), ProjectedY(), v\d
EndIf
EndIf
Next
End Function
Function Graph_FindMinD.Vertex(gr.Graph)
Local mind# = -1
Local rv.Vertex = Null
For v.Vertex = Each Vertex
If v\graphid = gr\id
If v\d <> -1
If mind = -1
rv = v
mind = v\d
Else
If v\d < mind
rv = v
mind = v\d
EndIf
EndIf
EndIf
EndIf
Next
Return rv
End Function
Function Graph_FindShortestPath(gr.Graph, src.Vertex, dest.Vertex)
Local u.Vertex
Local prevu.Vertex
If (gr=Null) Or (src=Null) Or (dest=Null) Or (src=dest) Then Return
gr\bestreach = Null
u = src
For v.Vertex = Each Vertex
v\p = Null
If v = src
v\d = 0
Else
v\d = -1
EndIf
Next
q.Graph = Graph_Copy(gr, 1) : Graph_SetVisible(q, False)
s.Graph = Graph_Create(2) : Graph_SetVisible(s, False)
qdest.Vertex = Graph_FindVertex(q, EntityX(dest\m), EntityY(dest\m), EntityZ(dest\m))
While q\vcount
prevu = u
u = Graph_FindMinD(q)
Graph_RemoveVertexShallow(q, u)
Graph_AddVertex(s, u)
If u = Null ; destination is unreachable
u = prevu ; rollback
Exit
EndIf
If u = qdest Then Exit
For i% = 0 To u\conidx-1
If (u\connection[i]\d=-1 Or u\connection[i]\d>(u\d + Vertex_GetCost(u, i)))
u\connection[i]\d = u\d + Vertex_GetCost(u, i)
u\connection[i]\p = u
EndIf
Next
Wend
v = u
; setup predecessors in gr Graph
While v\p <> Null
vv.Vertex = Graph_FindVertex(gr, EntityX(v\m), EntityY(v\m), EntityZ(v\m))
If v = u Then gr\bestreach = vv
vp.Vertex = Graph_FindVertex(gr, EntityX(v\p\m), EntityY(v\p\m), EntityZ(v\p\m))
vv\p = vp
v = v\p
Wend
; clean up
Graph_Delete(q)
Graph_Delete(s)
End Function |
Comments
None.
Code Archives Forum