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.
Select the layer with lines, and then from the Labels tab select Expression... from the Label using dropdown.
------------------------------
Peter Horsbøll Møller
Principal Presales Consultant | Distinguished Engineer
Precisely | Trust in Data
------------------------------