About Monkey 2 › Forums › Monkey 2 Programming Help › Node based path-finding
This topic contains 5 replies, has 4 voices, and was last updated by 
 Hezkore
 2 years, 1 month ago.
- 
		AuthorPosts
 - 
		
			
				
February 16, 2017 at 1:03 am #7167
I’m trying to figure out a simple way to do node based path-finding, but my math skills are terrible so it’s proven to be a bit too hard for me.
This is what I’ve got so far, it has no path-finding code.
Could someone point me in the right direction here, or help me out with some example?
At line 375 is where the path-finding code would go.Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388#Import "<std>"#Import "<mojo>"#Import "<mojox>"Using std..Using mojo..Using mojox..Class MyWindow Extends WindowGlobal pathPlaceStep:IntMethod New()Super.New("Simple Mojo Gui App",640,480,WindowFlags.Resizable)Node.camera.X=640/2Node.camera.Y=480/2For Local i:Int=0 Until 25New Node(Rnd(-640,640),Rnd(-480,480))NextClearColor=Color.DarkGreyClearEnabled=TrueEndMethod OnRender(canvas:Canvas) OverrideApp.RequestRender()canvas.DrawText("Click & Drag to Move node",0,0)canvas.DrawText("Ctrl & Drag to Link node",0,15)canvas.DrawText("Shift & Click to Insta-Link node",0,15*2)canvas.DrawText("Alt & Click to Remove node",0,15*3)canvas.DrawText("W,A,S,D to Move camera",0,15*4)canvas.DrawText("Numpad Minus to Remove node",0,15*5)canvas.DrawText("Numpad Plus to Add node",0,15*6)If Self.pathPlaceStep Thencanvas.DrawText("Space to Place path end",0,15*7)Elsecanvas.DrawText("Space to Place path start",0,15*7)EndifIf Keyboard.KeyDown(Key.W) Then Node.camera.Y+=2If Keyboard.KeyDown(Key.S) Then Node.camera.Y-=2If Keyboard.KeyDown(Key.A) Then Node.camera.X+=2If Keyboard.KeyDown(Key.D) Then Node.camera.X-=2If Keyboard.KeyHit(Key.KeypadPlus) ThenNew Node(Mouse.X-Node.camera.X,Mouse.Y-Node.camera.Y,Node.selectedNode)Node.selectedNode=Node.lastAddedNodeEndifIf Keyboard.KeyHit(Key.KeypadMinus) ThenIf Node.selectedNode ThenNode.selectedNode.Remove()ElseNode.MouseNode()If Node.lastMouseNode Then Node.lastMouseNode.Remove()EndifEndifIf Keyboard.KeyHit(Key.Space) ThenIf Self.pathPlaceStep thenSelf.pathPlaceStep=0Node.FindPath(Node.pathStartPos.x,Node.pathStartPos.y,Mouse.X-Node.camera.X,Mouse.Y-Node.camera.Y)ElseNode.ClearPath()Self.pathPlaceStep=1Node.pathStartPos=New Vec2f(Mouse.X-Node.camera.X,Mouse.Y-Node.camera.Y)Node.pathEndPos=New Vec2f(Mouse.X-Node.camera.X,Mouse.Y-Node.camera.Y)endifEndifNode.Update()Node.Draw(canvas)If Node.dragLink Or Node.moveNode ThenIf SwapInterval<>0 Then SwapInterval=0ElseIf SwapInterval<>1 Then SwapInterval=1EndifEndEndFunction Main()New AppInstanceNew MyWindowApp.Run()EndClass NodeGlobal list:List<Node>Global path:List<Node>Global camera:Vec2fGlobal selectedNode:NodeGlobal lastMouseNode:NodeGlobal lastAddedNode:NodeGlobal lastCloseNode:NodeGlobal dragLink:BoolGlobal moveNode:BoolGlobal pathStartNode:NodeGlobal pathEndNode:NodeGlobal pathStartPos:Vec2fGlobal pathEndPos:Vec2fField id:IntField x:FloatField y:FloatField links:List<Node>Field color:ColorField size:Int=12Method New(x:Float,y:Float,link:Node=Null)If Not Node.list Then Node.list=New List<Node>If Not Node.path Then Node.path=New List<Node>'Find unique ID for nodeLocal n:NodeLocal freeId:IntLocal checkId:IntRepeatfreeId=checkIdFor n=Eachin Node.listIf n.id=checkId Then'RETRY!!freeId=-1ExitEndifNextcheckId+=1Until freeId>=0Self.id=freeIdSelf.x=xSelf.y=yIf Not Self.links Then Self.links=New List<Node>If link Then Self.AddLink(link)Node.lastAddedNode=SelfNode.list.AddLast(self)EndMethod MouseHover:Bool()If Mouse.X-Node.camera.X>=Self.x-Self.size/2 And Mouse.Y-Node.camera.Y>=Self.y-Self.size/2 ThenIf Mouse.X-Node.camera.X<=Self.x+Self.size/2 And Mouse.Y-Node.camera.Y<=Self.y+Self.size/2Return TrueEndifEndReturn FalseEndMethod AddLink(node:Node)If Not node ThenPrint "No link node!"ReturnEndif'Check if selfIf Self=node ThenPrint "Link node is self!"ReturnEndif'Check if link already existsLocal n:NodeFor n=Eachin node.linksIf n=Self ThenPrint "Link already exists!"ReturnEndifNextFor n=Eachin Self.linksIf n=node ThenPrint "Link already exists!"ReturnEndifNextnode.links.AddLast(Self)Self.links.AddLast(node)EndMethod RemoveLink(node:Node)Self.links.Remove(node)node.links.Remove(Self)EndMethod Remove()If Node.selectedNode=Self Then Node.selectedNode=NullIf Node.lastMouseNode=Self Then Node.lastMouseNode=NullIf Node.lastAddedNode=Self Then Node.lastAddedNode=NullIf Node.lastCloseNode=Self Then Node.lastCloseNode=NullIf Self.links ThenFor Local n:Node=Eachin Self.linksn.RemoveLink(Self)NextEndifNode.list.Remove(Self)EndFunction MouseNode:Node()Node.lastMouseNode=NullFor Local n:Node=Eachin Node.listIf n.MouseHover() ThenNode.lastMouseNode=nReturn Node.lastMouseNodeEndifNextReturn NullEndFunction NodeClose:Node(x:Float,y:Float)Node.lastCloseNode=NullLocal dx:FloatLocal dy:FloatLocal dist:FloatLocal bestDist:FloatFor Local n:Node=Eachin Node.listdx=x-n.xdy=y-n.ydist=Sqrt(dx*dx + dy*dy)If Not Node.lastCloseNode Or dist<bestDist ThenbestDist=distNode.lastCloseNode=nEndifNextReturn Node.lastCloseNodeEndFunction NodeId:Node(id:int)For Local n:Node=Eachin Node.listIf n.id=id Then Return nNextReturn NullEndFunction Update()For Local n:Node=Eachin Node.listIf Node.selectedNode = n Thenn.color=Color.GreenElsen.color=Color.OrangeEndifNextIf Mouse.ButtonHit(MouseButton.Left) ThenNode.MouseNode()If Node.selectedNode ThenIf Not Node.lastMouseNode ThenNode.selectedNode=NullElseIf Node.selectedNode=Node.lastMouseNode ThenIf Keyboard.KeyDown(Key.LeftControl) Or Keyboard.KeyDown(Key.RightControl) ThenNode.dragLink=TrueElseNode.moveNode=TrueEndifElseIf Keyboard.KeyDown(Key.LeftShift) Or Keyboard.KeyDown(Key.RightShift) ThenNode.selectedNode.AddLink(Node.lastMouseNode)ElseIf Keyboard.KeyDown(Key.LeftAlt) Or Keyboard.KeyDown(Key.RightAlt) ThenNode.selectedNode.RemoveLink(Node.lastMouseNode)ElseNode.selectedNode=Node.lastMouseNodeEndifEndifEndifEndifElseNode.selectedNode=Node.lastMouseNodeEndifElseIf Mouse.ButtonDown(MouseButton.Left) ThenIf Node.dragLink ThenNode.MouseNode()If Node.lastMouseNode And Node.lastMouseNode<>Node.selectedNode ThenNode.lastMouseNode.color=Color.BlueEndifEndifIf Node.moveNode ThenNode.selectedNode.x=Mouse.X-Node.camera.XNode.selectedNode.y=Mouse.Y-Node.camera.YEndifElseIf Node.dragLink ThenIf Node.lastMouseNode Then Node.selectedNode.AddLink(Node.lastMouseNode)Node.dragLink=FalseEndifIf Node.moveNode ThenNode.moveNode=FalseEndifEndifEndifEndFunction Draw(canvas:Canvas)canvas.Translate(Node.camera.X,Node.camera.Y)Local n:NodeLocal n2:Nodecanvas.LineSmoothing=Truecanvas.LineWidth=3'Draw linksFor n=Eachin Node.listcanvas.Color=Color.BlueFor n2=Eachin n.linkscanvas.DrawLine(n.x,n.y,n2.x,n2.y)NextNext'Draw nodesFor n=Eachin Node.listcanvas.Color=n.colorcanvas.DrawOval(Int(n.x-n.size/2),Int(n.y-n.size/2),n.size,n.size)canvas.Color=Color.Whitecanvas.DrawText(n.id,n.x,n.y,0.5,0.5)Next'Draw dragging lineIf Node.dragLink Thencanvas.Color=Color.Bluecanvas.DrawLine(selectedNode.x,selectedNode.y,Mouse.X-Node.camera.X,Mouse.Y-Node.camera.Y)Endif'Draw pathcanvas.Color=Color.PuceIf Node.path.Count()<=0 Thencanvas.DrawLine(Node.pathStartPos.X,Node.pathStartPos.Y,Node.pathEndPos.X,Node.pathEndPos.Y)Elsecanvas.DrawLine(Node.pathStartPos.X,Node.pathStartPos.Y,Node.path.First.x,Node.path.First.y)Local lastNode:Node=Node.path.FirstFor n=Eachin Node.pathIf lastNode=n Then Continuecanvas.DrawLine(n.x,n.y,lastNode.x,lastNode.y)lastNode=nNextcanvas.DrawLine(Node.pathEndPos.X,Node.pathEndPos.Y,Node.path.Last.x,Node.path.Last.y)Endifcanvas.Color=Color.Pinkcanvas.DrawText("S",Int(Node.pathStartPos.X),Int(Node.pathStartPos.Y),0.5,0.5)If Int(Node.pathStartPos.X)<>Int(Node.pathEndPos.X) And Int(Node.pathStartPos.Y)<>Int(Node.pathEndPos.Y) thencanvas.DrawText("E",Int(Node.pathEndPos.X),Int(Node.pathEndPos.Y),0.5,0.5)EndifEndFunction ClearPath()Node.path.Clear()EndFunction FindPath(startX:Float,startY:Float,endX:Float,endY:Float)ClearPath()Node.pathStartNode=Node.NodeClose(startX,startY)Node.pathEndNode=Node.NodeClose(endX,endX)Node.pathStartPos.X=startXNode.pathStartPos.Y=startYNode.pathEndPos.X=endXNode.pathEndPos.Y=endY'Super pathfinding code here...'Just add some random path for nowNode.path.AddLast(Node.NodeId(8))Node.path.AddLast(Node.NodeId(5))Node.path.AddLast(Node.NodeId(11))Node.path.AddLast(Node.NodeId(17))Node.path.AddLast(Node.NodeId(0))'Print pathFor Local n:Node=Eachin Node.pathPrint n.idNextEndEndFebruary 16, 2017 at 4:20 am #7170Need to know finding rules. At least, can we go to the end point directly without nodes if end is near to start?
My version:
- Go through all nodes and find nearest point to the end by calculating minimal total distance:
- total = dist(start,node[i])+dist(node[i],end)
 - so we get nodeX, store it to the path-list
 - note, that end point should be in this check as any other nodes
 
 - Goto (2) but replacing ‘start’ with our ‘nodeX’. Until the nearest node will be ‘end’ point.
 
In specific case there will be only start and end points as result if any other node have longer distance.
February 16, 2017 at 9:35 pm #7181I think there’s a node/pathfinding demo in blitzmax!
February 16, 2017 at 11:30 pm #7182I think there’s a node/pathfinding demo in blitzmax!
samples/aaronkoolen/AStar/astar_demo.bmx?
EDIT: Removed possibly incorrect info.
@hezkore: I’m not sure I understand your requirements. Do you want to calculate the most efficient route through a set of given nodes?
February 17, 2017 at 11:12 pm #7189@impixi Yep!
I want to place a bunch of nodes and then set one of them as the start node and one as the ending node.
Then I want a list of the nodes that are needed to go by in order to get to the ending node.I’ve started to translate some Monkey X code I’ve found, but it’s tricky heh.
February 24, 2017 at 3:13 am #7269Here’s a translated example.
Click to place a few nodes, then drag a line between the nodes.
Hover over a node and press S to place the path start.
Do the same but press G to place the path goal.
Press Enter to calculate the path.Original code: http://www.monkey-x.com/Community/posts.php?topic=2155
Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500#Import "<std>"#Import "<mojo>"Using std..Using mojo..Const PATHNODE_RADIUS:Int=12Global START_NODE:PathNodeGlobal GOAL_NODE:PathNodeClass MyWindow Extends Window'stores mouse positionsField mx:IntField my:Int'bool to detect mouse pressingField mousePressed:Int'stores clicked nodesField node1:PathNodeField node2:PathNode'stores found pathField foundPath:PathField foundTime:IntMethod New(title:String="Simple mojo app",width:Int=640,height:Int=480,flags:WindowFlags=Null)Super.New(title,width,height,flags )EndMethod OnRender(canvas:Canvas) OverrideApp.RequestRender()OnUpdate()'draws mouse lineIf mousePressed = 1If Mouse.X<>mx Or Mouse.Y<>mycanvas.DrawLine(mx, my, Mouse.X, Mouse.Y)EndifEndif'draws node networkPathNode.DrawLinks(canvas)PathNode.DrawNodes(canvas)'draws pathIf foundPath<>Nullcanvas.Color=Color.Whitecanvas.DrawText(foundPath.PrintPath() + " " + foundTime + "ms", 10, 0)EndifEndMethod OnUpdate()'finds a pathIf Keyboard.KeyHit(Key.Enter)'sets up pathfinding routingfoundPath = NullPathFind.Setup( START_NODE, GOAL_NODE )'starts pathfindingfoundTime = Millisecs()Local result : Bool = PathFind.FindPath()foundTime = Millisecs() - foundTime'stores found pathIf result = True Then foundPath = PathFind.pathList.FirstEndif'sets start nodeIf Keyboard.KeyHit(Key.S)Local test : PathNode = PathNode.Touch( Mouse.X, Mouse.Y )If test <> Null Then START_NODE = testEndif'sets goal nodeIf Keyboard.KeyHit(Key.G)Local test : PathNode = PathNode.Touch( Mouse.X, Mouse.Y )If test <> Null Then GOAL_NODE = testEndif'handles mouseIf Mouse.ButtonDown(MouseButton.Left)'store initial mouse click location (used to detect mouse movement)If mousePressed = 0'grab mouse positionmx = Mouse.Xmy = Mouse.Y'grab clicked node if anynode1 = PathNode.Touch( mx, my )Endif'mouse has been pressedmousePressed = 1EndifIf Not Mouse.ButtonDown(MouseButton.Left) And mousePressed = 1'if we didnt click a path nodeIf node1 = Null'if the mouse position has not changed since we first clickedIf Mouse.X = mx And Mouse.Y = my'create a path nodePathNode.Create(mx, my)'position has moved so we have dragged an invisible lineElse'use the mouse path to find intersecting nodes and links and remove themPathNode.RemoveIntersectingNodes(mx,my,Mouse.X, Mouse.Y)PathNode.RemoveIntersectingLinks(mx,my,Mouse.X, Mouse.Y)Endif'if we did click inside a nodeElse'grab clicked node if anynode2 = PathNode.Touch( Mouse.X, Mouse.Y )'check if we intersected with another nodeIf node2<>Null And node2<>node1'create a linknode1.Link( node2 )EndifEndif'reset mousemousePressed = 0node1 = NullEndifEndEndFunction Main()New AppInstanceNew MyWindowApp.Run()EndClass PathField nodes:List<PathNode>Field travelledDistance:FloatField underestimate:FloatMethod New()Self.nodes=New List<PathNode>EndMethod Copy:Path()Local this:Path=New PathFor Local n:PathNode=Eachin Self.nodesthis.nodes.AddLast(n)Nextthis.travelledDistance=Self.travelledDistanceReturn thisEndMethod CalculateUnderestimate:Float( goal : PathNode )If goal = Null Then Return 0Self.underestimate=nodes.Last.Distance( goal.x, goal.y )Return Self.underestimateEndMethod PrintPath:String()Local output:StringFor Local this:PathNode = Eachin Self.nodesoutput=output + String( this.id )If this<>Self.nodes.Lastoutput+=" -> "EndifNextReturn outputEndFunction Create:Path( start : PathNode )Local this:Path = New Paththis.nodes.AddLast( start )Return thisEndEnd'extends the listClass PathfindList Extends List<Path>'compares score valueMethod Compare:Int(a:Path,b:Path )If a.travelledDistance+a.underestimate>b.travelledDistance+b.underestimate Then Return 1If a.travelledDistance+a.underestimate<b.travelledDistance+b.underestimate Then Return -1Return 0EndEnd'static pathfind classClass PathFindGlobal start:PathNodeGlobal goal:PathNodeGlobal pathList:PathfindList=New PathfindList'sets up the pathfindingFunction Setup(node1:PathNode, node2:PathNode)start=node1goal=node2pathList.Clear()pathList.AddLast(Path.Create(start))pathList.First.CalculateUnderestimate(node2)End'finds a pathFunction FindPath:Bool()Repeat'if pathList is empty then exitIf Not pathList Or pathList.Count()=0 Then Return False'if first path ends at goal then we have found our pathIf pathList.First.nodes.Last = goal Then Return True'extract the first pathLocal firstPath:Path=pathList.RemoveFirst()'extend path to all neighbours creating x new pathsFor Local neighbour:PathLink=Eachin firstPath.nodes.Last.linked'copy pathLocal newPath:Path = firstPath.Copy()'get the neighbour nodeLocal newNode:PathNode = neighbour.linkedNode'reject if loopFor Local child:PathNode = Eachin newPath.nodesIf child=newNodenewPath=NullExitEndifNext'if newPath is null we found a loopIf newPath'add new node and travel costnewPath.nodes.AddLast( newNode )newPath.travelledDistance = newPath.travelledDistance + neighbour.costEndif'For all paths that End at the same node, keep only the shortest one.If newPath<>NullFor Local shortPath:Path=Eachin pathList'if ends in the same nodeIf shortPath.nodes.Last=newNode'keep the shortestIf shortPath.travelledDistance <= newPath.travelledDistancenewPath = NullExitElsepathList.RemoveEach( shortPath )ExitEndifEndifNextEndif'if we still have a valid new path add it to the listIf newPath <> NullpathList.AddLast( newPath )newPath.CalculateUnderestimate( goal )EndifNext'Sort all paths by total underestimate, shortest first.pathList.Sort(True)ForeverReturn FalseEndEndClass PathLinkField linkedNode:PathNodeField cost:FloatFunction Create:PathLink(node1:PathNode, node2:PathNode)Local this:PathLink=New PathLinkthis.linkedNode=node2this.cost=node1.Distance(node2.x, node2.y)Return thisEndEndClass PathNodeGlobal nodeCount:IntGlobal nodeList:List<PathNode>Field nodeId:List<PathNode>.NodeField id:IntField x:IntField y:IntField linked:List<PathLink>'links two nodesMethod Link(other:PathNode)'if same node then exitIf other = Self Then Return'if link already exists then exitFor Local this:PathLink=Eachin Self.linkedIf this.linkedNode=other Then ReturnNext'create linksother.linked.AddLast(PathLink.Create(other,Self))Self.linked.AddLast(PathLink.Create(Self,other))End'draws node, coloured to indicate start/goalMethod Draw(canvas:Canvas)canvas.Color=Color.Whitecanvas.DrawOval(Self.x - PATHNODE_RADIUS, Self.y - PATHNODE_RADIUS, PATHNODE_RADIUS * 2, PATHNODE_RADIUS * 2)canvas.Color=Color.BlackIf GOAL_NODE=Self Then canvas.Color=Color.RedIf START_NODE=Self Then canvas.Color=Color.Greencanvas.DrawOval(Self.x - PATHNODE_RADIUS + 1, Self.y - PATHNODE_RADIUS + 1, PATHNODE_RADIUS * 2 - 2, PATHNODE_RADIUS * 2 - 2)canvas.Color=Color.Whitecanvas.DrawText(Self.id, Self.x, Self.y, 0.5, 0.5)End'draws a line to all linked nodesMethod DrawLinked(canvas:Canvas)canvas.Color=Color.WhiteFor Local this:PathLink = Eachin Self.linkedcanvas.DrawLine(Self.x, Self.y, this.linkedNode.x, this.linkedNode.y)NextEnd Method'returns distance from self to point x, yMethod Distance:Float(px:Int, py:Int)Local dx:Int=px-Self.xLocal dy:Int=py-Self.yReturn Sqrt(dx*dx+dy*dy)End MethodFunction Create:PathNode(px:Int, py:Int)If Not nodeList Then nodeList=New List<PathNode>nodeCount=nodeCount+1Local this:PathNode=New PathNode''Find unique ID for nodeLocal n:PathNodeLocal freeId:IntLocal checkId:IntRepeatfreeId=checkIdFor n=Eachin nodeListIf n.id=checkId Then'RETRY!!freeId=-1ExitEndifNextcheckId+=1Until freeId>=0this.id=freeIdthis.x=pxthis.y=pythis.nodeId=nodeList.AddLast(this)this.linked=New List<PathLink>Return thisEnd FunctionFunction DrawNodes(canvas:Canvas)If Not nodeList Or nodeList.Count()=0 Then ReturnFor Local this:PathNode=Eachin nodeListthis.Draw(canvas)NextEndFunction DrawLinks(canvas:Canvas)If Not nodeList Or nodeList.Count()=0 Then ReturnFor Local this : PathNode = Eachin nodeListthis.DrawLinked(canvas)NextEndFunction Touch:PathNode(px:Int, py:Int)If Not nodeList Or nodeList.Count()=0 Then Return Null'loop all nodes and return if we are insideFor Local this:PathNode=Eachin nodeListIf this.Distance(px,py)<PATHNODE_RADIUSReturn thisEndifNextReturn NullEndFunction RemoveIntersectingNodes(x1:Int, y1:Int, x2:Int, y2:Int)If Not nodeList Then ReturnFor Local this:PathNode=Eachin nodeList'if line is intersecting the nodeIf DistanceToLineSegment( x1, y1, x2, y2, this.x, this.y ) <= PATHNODE_RADIUS'find all linked nodes to this oneFor Local link : PathLink = Eachin this.linked'loop all of their links and remove link to thisLocal testNode : PathNode = link.linkedNodeFor Local rLink : PathLink = Eachin testNode.linkedIf rLink.linkedNode = thistestNode.linked.RemoveEach( rLink )ExitEndifNextNext'remove the nodethis.nodeId.Remove()EndifNextEndFunction RemoveIntersectingLinks(x1:Int, y1:Int, x2:Int, y2:Int)If Not nodeList Then Return'cycle all nodesFor Local this:PathNode=Eachin nodeList'cycle all linksFor Local link:PathLink=Eachin this.linked'if the line intersects the linkIf Intersect(x1,y1,x2,y2,this.x,this.y,link.linkedNode.x,link.linkedNode.y )'remove the linkthis.linked.RemoveEach( link )'check and remove link from other nodeFor Local rLink:PathLink=Eachin link.linkedNode.linkedIf rLink.linkedNode=thislink.linkedNode.linked.RemoveEach(rLink)ExitEndifNextEndifNextNextEndEnd' 2D math functions by Jasu'http://blitzbasic.com/codearcs/codearcs.php?code=2180Function Intersect:Int(x1:Float, y1:Float, x2:Float, y2:Float, x3:Float, y3:Float, x4:Float, y4:Float)' This Function returns True If lines x1,y1,x2,y2 And x3,y3,x4,y4 intersect at some point.Return (Orientation(x1, y1, x2, y2, x3, y3) <> Orientation(x1, y1, x2, y2, x4, y4)) And (Orientation(x3, y3, x4, y4, x1, y1) <> Orientation(x3, y3, x4, y4, x2, y2))EndFunction Orientation:Int(x1:Float,y1:Float, x2:Float,y2:Float, Px:Float,Py:Float)' Linear determinant of the 3 points.' This Function returns the orientation of px,py on line x1,y1,x2,y2.' Look from x2,y2 To the direction of x1,y1.' If px,py is on the right, Function returns +1' If px,py is on the left, Function returns -1' If px,py is directly ahead Or behind, Function returns 0Return Sgn((x2-x1)*(Py-y1)-(Px-x1)*(y2-y1))EndFunction DistanceToLineSegment:Float(x1:Float, y1:Float, x2:Float, y2:Float, Px:Float, Py:Float)' This Function calculates the distance between a line segment And a point.' So this Function is useful To determine If line intersects a circle.' To also determine the point on the line x1,y1,x2,y2 which is the closest To px,py , use Function NearestPointInLine#Local Dx : FloatLocal Dy : FloatLocal Ratio : FloatIf (x1 = x2) And (y1 = y2) ThenReturn Sqrt( (Px-x1)*(Px-x1)+(Py-y1)*(Py-y1) )ElseDx = x2 - x1Dy = y2 - y1Ratio = ((Px - x1) * Dx + (Py - y1) * Dy) / (Dx * Dx + Dy * Dy)If Ratio < 0 ThenReturn Sqrt( (Px-x1)*(Px-x1)+(Py-y1)*(Py-y1) )Elseif Ratio > 1 ThenReturn Sqrt( (Px-x2)*(Px-x2)+(Py-y2)*(Py-y2) )ElseReturn Sqrt((Px - ((1 - Ratio) * x1 + Ratio * x2))*(Px - ((1 - Ratio) * x1 + Ratio * x2))+(Py - ((1 - Ratio) * y1 + Ratio * y2))*(Py - ((1 - Ratio) * y1 + Ratio * y2)))EndifEndifEnd - Go through all nodes and find nearest point to the end by calculating minimal total distance:
 - 
		AuthorPosts
 
You must be logged in to reply to this topic.