Rotation and transformation matrix

Hi,

I'm struggling with placing a cell along an arc in VBA.

I have a Complex Chain where I will place a cell along the whol chain with a fixed distance.

I have solved the rotation on the "Line" part of the chainm but having trouble with the arc.

The rotation is almost correct, but almost doesn't count :-)

Any one have a suggestion?

The code snippet for placing the cell:

Sub showLineElm(LinElm As ComplexStringElement)
  Dim elm As ElementEnumerator
  Dim aelm As ArcElement
  Dim lelm As LineElement
  Dim oPH As PropertyHandler
  Dim lastsegment As String
  Dim streng As String, streng1 As String
  Dim start As Point3d
  Dim skala As Point3d
  Dim oCell As CellElement
  Dim z As Integer
  Dim ant_cell As Double, distance As Double
  Dim vinkel As Double
  Dim mtrxRotation As Matrix3d
 
  skala.X = 1
  skala.Y = 1
  skala.z = 1
  If LinElm.Type = msdElementTypeComplexString Then
    If LinElm.IsTraversableElement Then
      Set elm = LinElm.GetSubElements
      Do While elm.MoveNext

        Select Case elm.Current.Type
          Case msdElementTypeLine
            Set lelm = elm.Current.AsLineElement
            lastsegment = "Segments[" & (lelm.VerticesCount - 2) & "]."
            Set oPH = CreatePropertyHandler(lelm)
            oPH.SelectByAccessString (lastsegment & "Start")
            start = oPH.GetValueAsPoint3d
            oPH.SelectByAccessString (lastsegment & "Direction")
            streng = oPH.GetValue
            vinkel = Degrees(CDbl(streng))
            mtrxRotation = Matrix3dFromAxisAndRotationAngle(2, CDbl(streng))
            Set oCell = CreateCellElement2("cellname", start, skala, True, mtrxRotation)
            ActiveModelReference.AddElement oCell
            ant_cell = lelm.Length / 0.854
            ant_cell = ant_cell \ 1
            distance = 0
            For z = 1 To ant_cell
              distance = distance + 0.854
              If distance > lelm.Length Then
                Exit For
              End If
              start = lelm.PointAtDistance(distance)
              Set oCell = CreateCellElement2("cellname", start, skala, True, mtrxRotation)
              ActiveModelReference.AddElement oCell
            Next z

          Case msdElementTypeArc
            Set aelm = elm.Current.AsArcElement
            Set oPH = CreatePropertyHandler(aelm)
            oPH.SelectByAccessString ("SweepAngle")
            vinkel = oPH.GetValue
            mtrxRotation = Matrix3dFromAxisAndRotationAngle(2, vinkel)
            start = aelm.StartPoint
            Set oCell = CreateCellElement2("cellname", start, skala, True, mtrxRotation)
            distance = 0
            oCell.Transform Transform3dFromMatrix3dAndFixedPoint3d(mtrxRotation, start)
            ActiveModelReference.AddElement oCell
            ant_cell = aelm.Length / 0.854
            ant_cell = ant_cell \ 1
            For z = 1 To ant_cell
              distance = distance + 0.854
              If distance > aelm.Length Then
                Exit For
              End If
              start = aelm.PointAtDistance(distance)
              Set oCell = CreateCellElement2("cellname", start, skala, True, mtrxRotation)
              oCell.Transform Transform3dFromMatrix3dAndFixedPoint3d(mtrxRotation, start)
              ActiveModelReference.AddElement oCell
            Next z
        End Select
      Loop
    End If
  End If
errExit:
End Sub    'showLineElm

  • Hi Finn,

    please read and follow MicroStation Programming forum best practices and to share required information like what MicroStation version do you use. Also some example file would be nice.

    Also please edit your post and use Insert > Insert Code tool to share your code in a proper form. Personally, long time ago I decided to don't read any code formatted as plain text, because it's ugly, hardly readable and time consuming.

    The rotation is almost correct

    What does it mean. Why you don't provide better explanation?

    Any one have a suggestion?

    Split your code into more functions with exactly specified responsibility (at least to process linear and arc elements). Approach "one function will do everything" always leads to dirty and buggy code.

    Why do you use PropertyHandler object here? It's "the last chance" tool, but I am pretty sure to use it in any code processing elements is wrong. It's not only much slower than direct access to element properties, but I am also not quite sure about a precision of values returned.

    With regards,

      Jan

  • Magic Numbers

    ant_cell = lelm.Length / 0.854

    In addition to Jan's comments, avoid using magic numbers...

    distance = distance + 0.854

    ... especially when those magic numbers are used plurally.

    Prefer to use a symbolic constant.  It will help you in 2 years time when you come to maintain or improve your code!

    Const ALPHA_FACTOR As Double = 0.854
    ...
    ant_cell = aelm.Length / ALPHA_FACTOR
    ...
    distance = distance + ALPHA_FACTOR

    Use Helpful Procedure Names

    The code snippet for placing the cell:

    Sub showLineElm(LinElm As ComplexStringElement)

    Your subroutine name is at odds with your comment! Comments wear out: they become disconnected from their object. Prefer to make the subroutine name tell its own story...

    Sub CreateCellAtOffset (ByVal oTraversableElement As ComplexStringElement)

     
    Regards, Jon Summers
    LA Solutions

  • Jan,

    Thought I was OK by tagging the post with MicroStation V8i Open mouth

    My version is: 08.11.09.459 (SelectSeries 3).

    This is what I mean by "Close, but no cigar", the blue ones are placed manually with the correct rotation, the black cells are drawn by my program.

    The code:

    Sub showLineElm(LinElm As ComplexStringElement)
      Dim elm As ElementEnumerator
      Dim aelm As ArcElement
      Dim lelm As LineElement
      Dim oPH As PropertyHandler
      Dim lastsegment As String
      Dim streng As String, streng1 As String
      Dim start As Point3d
      Dim skala As Point3d
      Dim oCell As CellElement
      Dim z As Integer
      Dim ant_cell As Double, distance As Double
      Dim vinkel As Double
      Dim mtrxRotation As Matrix3d
      
      skala.X = 1
      skala.Y = 1
      skala.z = 1
      If LinElm.Type = msdElementTypeComplexString Then
        If LinElm.IsTraversableElement Then
          Set elm = LinElm.GetSubElements
          Do While elm.MoveNext
            Select Case elm.Current.Type
              Case msdElementTypeLine
                Set lelm = elm.Current.AsLineElement
                lastsegment = "Segments[" & (lelm.VerticesCount - 2) & "]."
                Set oPH = CreatePropertyHandler(lelm)
                oPH.SelectByAccessString (lastsegment & "Start")
                start = oPH.GetValueAsPoint3d
                oPH.SelectByAccessString (lastsegment & "Direction")
                streng = oPH.GetValue
                vinkel = Degrees(CDbl(streng))
                mtrxRotation = Matrix3dFromAxisAndRotationAngle(2, CDbl(streng))
                Set oCell = CreateCellElement2("cellname", start, skala, True, mtrxRotation)
    '            oCell.GraphicGroup = ggNum
                ActiveModelReference.AddElement oCell
                ant_cell = lelm.Length / 0.854
                ant_cell = ant_cell \ 1
                distance = 0
                For z = 1 To ant_cell
                  distance = distance + 0.854
                  If distance > lelm.Length Then
                    Exit For
                  End If
                  start = lelm.PointAtDistance(distance)
                  Set oCell = CreateCellElement2("cellname", start, skala, True, mtrxRotation)
                  ActiveModelReference.AddElement oCell
                Next z
              Case msdElementTypeArc
                Set aelm = elm.Current.AsArcElement
                Set oPH = CreatePropertyHandler(aelm)
                oPH.SelectByAccessString ("SweepAngle")
                vinkel = oPH.GetValue
                mtrxRotation = Matrix3dFromAxisAndRotationAngle(2, vinkel)
                start = aelm.StartPoint
                Set oCell = CreateCellElement2("cellname", start, skala, True, mtrxRotation)
    '            oCell.GraphicGroup = ggNum
                distance = 0
                oCell.Transform Transform3dFromMatrix3dAndFixedPoint3d(mtrxRotation, start)
               
                ActiveModelReference.AddElement oCell
                ant_cell = aelm.Length / 0.854
                ant_cell = ant_cell \ 1
                For z = 1 To ant_cell
                  distance = distance + 0.854
                  If distance > aelm.Length Then
                    Exit For
                  End If
                  start = aelm.PointAtDistance(distance)
                  Set oCell = CreateCellElement2("cellname", start, skala, True, mtrxRotation)
                oCell.Transform Transform3dFromMatrix3dAndFixedPoint3d(mtrxRotation, start)
                  ActiveModelReference.AddElement oCell
                Next z
            End Select
          Loop
        End If
      End If
    errExit:
    End Sub 'showLineElm
    

    The code is still "Work in Progress" and therefor not that pretty yet.

    Regards,

     

    Finn Mejding

    CAD Manager

    Railway and Metro

    COWI

  • Thought I was OK by tagging the post with MicroStation V8i

    Ok, you did it, but it's not accordingly the forum best practices, so a probability anybody will check tags in the first place is close to zero in my opinion.

    As defined in the article I linked, the version and language should be noted in subject like "[V8i VBA] Rotation and transformation matrix" and it's what frequent visitors of this group expect, not tags.

    The code is still "Work in Progress" and therefor not that pretty yet.

    In my opinion (but it's really subjective personal ;-) "the code prettiness" is a way how to write code quickly and efficiently, not the final state how code looks like when it's finished.

    What about my question about PropertyHandlers, this is something I recommend to remove in the first step (or to argue why this non standard construction is needed).

    With regards,

      Jan

  • I'm struggling with placing a cell along an arc in VBA

    Here's an example VBA project that may help...

    Place Cell Along Linear Element

    It probably doesn't do exactly what you want, but it's a good place to start.  The startling bit is probably the use of a B-Spline curve to help calculate point-at-a-distance and tangent-at-a-distance for each cell placement.

     
    Regards, Jon Summers
    LA Solutions

    Answer Verified By: Finn Mejding 

  • I'm not here to question your coding...Are you trying to create a tool that will do just this for you, or is it a part of a larger workflow you are trying to automate?

    MaryB

    Power GeoPak 08.11.09.918
    Power InRoads 08.11.09.918
    OpenRoads Designer 2021 R2

        

  • MaryB,

    This will be part of a toolbox do different automated processes.

    Bu I guess I will use this as a "motor" for many of the tools. Ex. placing Sleepers along an alignment. 

    Regards,

     

    Finn Mejding

    CAD Manager

    Railway and Metro

    COWI

  • Thanks Jon, that really helpme.

    I have the rotation matrix in place now, just need to fit the numger of cells.

    Regards,

     

    Finn Mejding

    CAD Manager

    Railway and Metro

    COWI