MapInfo Pro

 View Only

MapInfo Monday: Line Direction

  • 1.  MapInfo Monday: Line Direction

    Employee
    Posted 20 days ago
    Edited by Peter Møller 6 days ago

    I have been looking to write this article since the beginning of the year.

    @Ryan Cook asked a question about calculating the line direction. He was looking for a way to understand the direction of the dual carriageways. He wanted to update these with the compass direction (N, S; E, & W) they were heading in. To do this, he needed to know the direction they were heading.

    The answer involved the DrawTools add-in from the MapInfo Marketplace and a registered function from this tool.

    Happy #MapInfoMonday - or should I say Merry #MapInfoMonday?

    Calculating the Direction of a (Poly)line

    The direction of a line can be useful when working with spatial data, especially if the line direction is intentional. For a road, it can illustrate the direction of the traffic, that is, for a one-way road, of course. For a river, it can illustrate the flow of the water. Same with a water or sewer pipe, it can illustrate the flow of water in the pipe. These are just a few examples.

    The DrawTools add-in exposes a custom MapBasic function to the MapInfo Pro interface, allowing MapInfo Pro users to benefit from this function. This is how the add-in exposes the function. The RBNregisterFunctionAsPublic() function can be found in the RIBBONLib module.

    nResult = RBNRegisterFunctionAsPublic("OBJDirection", "DTLineDirection", "Calculates the direction of a (poly)line, East is zero, counter-clockwise")

    When you register a custom function as a public function, you can give it an alias. Above, you can see that I have chosen to give the alias DTLineDirection to the function OBJDirection. The prefix DT refers to DrawTools.

    When you calculate the direction of a simple line, you calculate the direction from the first coordinate pair to the second coordinate pair.

    For polylines, it can be a bit trickier. A polyline can hold several line segments, so which segment would you calculate the direction based on? Or would you calculate the direction from the first node in the first segment to the last node in the last segment? I decided to keep it simple and only calculate a direction for polylines with one segment.

    The exposed function grabs the coordinate pairs from the object passed to the function, and then it calls another function to do the actual calculation of the direction from the coordinate pair: MATHGetDirection().

    Now, here's something you probably didn't know about me: Math isn't my superpower. I have always thought that there must be a better way than this. So maybe one of you can come up with a better formula for calculating the direction?

    Here is the formula that I used, and have used for years:

    '*******************************************************************************
    Function MATHGetDirection(ByVal fStartX As Float, ByVal fStartY As Float, ByVal fEndX As Float, ByVal fEndY As Float) As Float
    
    Dim	fDirection As Float
    
    OnError GoTo ErrorOccured
    
    MATHGetDirection = 0
    
    	'//Checking for vertical dirction
    	If (fEndX - fStartX) = 0 Then
    		'//not allowed to divide by zero...
    		If fEndY > fStartY Then
    			MATHGetDirection	= 90	'degrees
    		Else
    			MATHGetDirection	= 270	'degrees
    		End If
    		Exit Function
    	End If
    
    	'//Checking for horisontal dirction
    	If (fEndY - fStartY) = 0 Then
    		If (fEndX < fStartX) Then
    			MATHGetDirection = 180	'degrees
    		ElseIf (fEndX > fStartX) Then
    			MATHGetDirection = 0	'degrees
    		End If
    		Exit Function
    	End If
    
    	fDirection = Atn((fEndY - fStartY) / (fEndX - fStartX)) * RAD_2_DEG	'//Converting from RAD to Degrees
    
    	If (fEndX < fStartX) And (fEndY > fStartY) Then
    		'tEnd is northwest of tStart
    		fDirection = fDirection + 180	'degrees
    	ElseIf (fEndX < fStartX) And (fEndY < fStartY) Then
    		'tEnd is southwest of tStart
    		fDirection = fDirection + 180	'degrees
    	End If
    
    	MATHGetDirection = MATHGetValidDirection(fDirection)
    
    	Exit Function
    '-------------------------
    ErrorOccured:
    	Call ERRCreate(Err(), Error$(), "MATHGetDirection")
    	Call ERRShow()
    
    End Function
    
    '*******************************************************************************
    Function MATHGetValidDirection(ByVal fDirection As Float) As Float
    
    OnError GoTo ErrorOccured
    
    MATHGetValidDirection = fDirection
    
    	'//fDirection should be less than or equal to 360 degress
    	Do Until fDirection <= 360
    		fDirection = fDirection - 360	'//degrees
    	Loop
    	'//fDirection should be more than or equal to 0 degress
    	Do Until fDirection >= 0
    		fDirection = fDirection + 360	'//degrees
    	Loop
    
    MATHGetValidDirection = fDirection
    
    	Exit Function
    '-------------------------
    ErrorOccured:
    	Call ERRCreate(Err(), Error$(), "MATHGetValidDirection")
    	Call ERRShow()
    
    End Function
    

    The two functions can also be found in the MATHLib module.

    Please note that these functions will calculate the direction in the way MapInfo Pro deals with angles/directions. East is 0 degrees, North is 90 degrees, West is 180 degrees, and South is 270 degrees. 

    Anyway, once you have downloaded and installed DrawTools from the MapInfo Marketplace, you will have access to several functions registered by DrawTools, such as DTLineDirection().

    This function can be used to update a column with the direction, or you can label your lines with the direction.

    image
    Select the layer with lines, and then from the Labels tab select Expression... from the Label using dropdown.
    image
    In the Expression dialog, you can find the DTLineDirection function in the Functions list. Now position the cursor inside the parentheses and simply type OBJ or pick it from the Columns list. It's not important if you use the keyword OBJ or Object as you can see in the image.
    Click the OK button to close the dialog and then turn on Auto Labels for your layer.
    image
    I hope you found this useful.



    ------------------------------
    Peter Horsbøll Møller
    Principal Presales Consultant | Distinguished Engineer
    Precisely | Trust in Data
    ------------------------------