Questions similar to this appear on the Bentley Discussion Groups. This question appeared in the MicroStation discussion group.
Q
A
A line is straight when all its vertices are colinear.
MicroStation provides a simple line element (VBA msdElementTypeLine
) that has two vertices:
start and end.
A simple line element is always colinear.
The line-string element (VBA msdElementTypeLineString
) has from 2 to 5,000 vertices.
A colinear line-string requires that each set of three consecutive vertices are colinear.
The screenshot shows three lines …
msdElementTypeLine
, which must be colinear.
msdElementTypeLineString
)
msdElementTypeLineString
) that has three vertices
We can test a line-string to determine if is straight.
To implement that test, we borrow a function from the MDL library: mdlVec_colinear
.
When we use an MDL function we must declare it in our VBA module. The declaration looks like this …
' ---------------------------------------------------------------------
' Declare MDL functions at top of your VBA module, before any procedures
' mdlVec_colinear tests whether three points are colinear
' ---------------------------------------------------------------------
Declare PtrSafe Function mdlVec_colinear Lib "stdmdlbltin.dll" (ByRef pointArrayP As Point3d) As Long
Here's a VBA wrapper around that function …
' ---------------------------------------------------------------------
' PointsColinear
' Wrapper around MDL function mdlVec_colinear. Most MDL functions work
' with Units-of-Resolution (UORs). We need to convert VBA's units,
' which are DGN master units, to UORs so that function works as
' expected.
' Returns True if three points are colinear
' ---------------------------------------------------------------------
Private Function PointsColinear(ByRef points() As Point3d) As Boolean
Dim uors(0 To 2) As Point3d
Dim uorPerMaster As Double
uorPerMaster = ActiveModelReference.UORsPerMasterUnit
Dim i As Integer
For i = 0 To 2
uors(i) = Point3dScale(points(i), uorPerMaster)
Next i
Dim status As Long
status = mdlVec_colinear(uors(0))
If 0 = status Then
PointsColinear = False
Else
PointsColinear = True
End If
End Function
Here's a VBA procedure to test that function …
Sub TestPointsColinear() Debug.Print "+ TestPointsColinear" Dim points(0 To 2) As Point3d points(0) = Point3dFromXYZ(0.315503012863086, 0.440172369410825, 0) points(1) = Point3dFromXYZ(0.60622419153676, 0.308341356545869, 0) points(2) = Point3dFromXYZ(0.85221903502987, 0.492407299036562, 0) If PointsColinear(points) Then Debug.Print "Points are colinear" Else Debug.Print "Points are not colinear" End If End Sub
And here's a VBA procedure that will extract vertices from a LineElement
.
It relies on known Element IDs for the line elements — you'll have to
modify those IDs to match your DGN model.
Public Sub Main() Debug.Print "+ Example of PointsColinear" Dim msg As String Dim lineId As DLong ' Change these to the element IDs of lines or line-strings in your DGN model Const SingleLineID As Long = 1016 Const BentLineID As Long = 1017 Const StraightLineID As Long = 1018 lineId = DLongFromLong(BentLineID) Dim oLine As LineElement Set oLine = ActiveModelReference.GetElementByID(lineId) oLine.IsHighlighted = True Select Case oLine.Type Case msdElementTypeLine msg = "Line element is always colinear" ShowMessage msg, msg Debug.Print msg Case msdElementTypeLineString If (3 = oLine.VerticesCount) Then If PointsColinear(oLine.GetVertices) Then msg = "Line-string element ID " & DLongToString(lineId) & " is colinear" ShowMessage msg, msg, msdMessageCenterPriorityWarning Debug.Print msg Else msg = "Line-string element ID " & DLongToString(lineId) & " is not colinear" ShowMessage msg, msg, msdMessageCenterPriorityInfo Debug.Print msg End If Else msg = "This example requires a line-string having exactly 3 vertices" ShowMessage msg, msg, msdMessageCenterPriorityWarning Debug.Print msg End If Case Else msg = "Can't determine colinearity of element type " & CStr(oLine.Type) ShowMessage msg, msg, msdMessageCenterPriorityWarning Debug.Print msg End Select ' Release memory Set oLine = Nothing End Sub