VBA to place data point at intersection of selected lines

I need some help on this.  I have a grid of lines/arcs that I need to be able to select and run the VBA and have it place a data point at the all the intersections of the selected elements.  I have done some reading online, but I dont know enough about VBA in Microstation to get started.  I have attached a screen shot of the grid I am working with.  Actually I am trying to locate these points and using the tracking tool in InRoads I need to find surface elevations at all the intersection points.  I think I can select the lines and then activate the tracking tool in InRoads and then run the VBA to place a data point at all the intersections.  Any help will be greatly appreciated.  

Parents
  • Unknown said:
     I have attached a screen shot ...

    A screen-shot is good, but a DGN file is better.  We all use MicroStation, so a DGN file illustrates better the data you have.

    In this case, it's important to know about your dimensionality.  Presumably this is a 3D model, but what about your grid?  Are all those lines (a) planar and (b) do they lie on the same plane?  We can't deduce answers to those questions from a screen-shot.

    Finding Lines

    Follow Stefan's suggestion: use the ModelReference.Scan method to get an ElementEnumerator of lines.  Here's an example of a VBA project to collect lines.

     
    Regards, Jon Summers
    LA Solutions

  • Example.dgnJon,  I have attached a DGN that is similar to what I am working with.  I have deleted everything except the lines I am working with in this VBA.  I actually don't want to scan the entire file because the file will likely contain elements that I don't need to find the intersection of.  I want to be able to make a selection of lines and arcs and run the VBA to find all the intersections between the selected elements then have the VBA do the equivalent of left clicking (placing a data point) at the coordinate of the intersection.  The file I am working with is actually 2D because I need to get the surface elevations from InRoads tracking tool.

  • DGN Files and Models

    Unknown said:
     I actually don't want to scan the entire file

    Graphic elements are stored in models.  Models are stored in DGN files.  A DGN file will often contain multiple models.

    Consequently, you scan a model, not a file.  The VBA object ActiveModelReference is probably what you will work with most.

    Unknown said:
    The [model] will likely contain elements that I don't need to find

    That's normal: you set the properties of an ElementScanCriteria object to restrict the model scan.  That might be, in your case, line elements; or elements on a particular level.

    Unknown said:
     I want to be able to make a selection of lines and arcs and run the VBA to find all the intersections between the selected elements

    Create a list of candidate elements.  Then compare each candidate with all other candidates to find intersections.

    It's useful if you can differentiate between types of candidates.  From your DGN model it looks like you have one set of lines on level 1_RT_FLANGE_BEAM_2 and another set on level 1T_Lines.  You can build two lists, then use VBA method GetIntersectionPoints on a pair obtained from both lists.

    Pillage and Adapt

    Use the VBA example I cited and others you will find in VBA help.  Substitute your level names in that example — see what results you get.

     
    Regards, Jon Summers
    LA Solutions

Reply
  • DGN Files and Models

    Unknown said:
     I actually don't want to scan the entire file

    Graphic elements are stored in models.  Models are stored in DGN files.  A DGN file will often contain multiple models.

    Consequently, you scan a model, not a file.  The VBA object ActiveModelReference is probably what you will work with most.

    Unknown said:
    The [model] will likely contain elements that I don't need to find

    That's normal: you set the properties of an ElementScanCriteria object to restrict the model scan.  That might be, in your case, line elements; or elements on a particular level.

    Unknown said:
     I want to be able to make a selection of lines and arcs and run the VBA to find all the intersections between the selected elements

    Create a list of candidate elements.  Then compare each candidate with all other candidates to find intersections.

    It's useful if you can differentiate between types of candidates.  From your DGN model it looks like you have one set of lines on level 1_RT_FLANGE_BEAM_2 and another set on level 1T_Lines.  You can build two lists, then use VBA method GetIntersectionPoints on a pair obtained from both lists.

    Pillage and Adapt

    Use the VBA example I cited and others you will find in VBA help.  Substitute your level names in that example — see what results you get.

     
    Regards, Jon Summers
    LA Solutions

Children
  • Philip,

    again, use ActiveModelReference.GetSelectedElements to get all the selected elements.

    (Would be good to tell us your improvements or send the code you produced until now, looks like we do a lot of double posting right now.)

    Regards, Stefan.

  • Ok.   Here is my code so far.  It is working ok and it is finding the intersections but I have a couple of problems.  The first is that when I select the lines and run the VBA it will usually find two intersection points at each intersection each with apparently different rotations so it will put two data points at each intersection which is not ideal.  I think this has something to do with the Matrix3dIsIdentity when finding the intersection but I don't know how to make it ignore the rotation and only find one intersection point.  The other thing is that I need it to process the selected elements against all visible levels in View 1 not the level that I have defined in the VBA code.  Basically I need the end users to be able to select the elements and turn the level on that they want to process the selected elements against and run the VBA.  I need to assign all visible levels to the  ScanEnumerator variable.

    LabelIntersections.mvba

     

  • Unknown said:
     I think this has something to do with the Matrix3dIsIdentity

    p = el1.AsIntersectableElement.GetIntersectionPoints(el2, Application.Matrix3dIsIdentity)

    It's a good job you mentioned that!  CAD apps, including MicroStation, use 3D transforms and matrices in their geometric computations.  In MicroStation VBA, a rotation is defined by a Matrix3D user defined type (UDT).

    That method takes a Matrix3D to inform it of any required rotation to consider when calculating intersections.  You often provide a zero rotation (the identity matrix), given by function Matrix3dIdentity.  You've written Matrix3dIsIdentity, which answers the question "Is this a zero-rotation matrix?" with a Boolean answer, not a Matrix3D.

    I'm surprised that you didn't see a compilation error.  Try this instead...

    p = el1.AsIntersectableElement.GetIntersectionPoints(el2, Application.Matrix3dIdentity)

     
    Regards, Jon Summers
    LA Solutions

  • Hi Philip,

    good job so far.

    I think Jons suggestion should do the job.

    And you might find this function useful, which includes all visible level of a certain view into a scancriteria.

    (Untested.)

    Function AddVisibleLevelsToScanCriteria(sc As ElementScanCriteria, viewindex As Integer)

       Dim vw As View

       Dim lv As Level

       Set vw = ActiveDesignFile.Views(viewindex)

       For i = 1 To ActiveDesignFile.Levels.Count

           Set lv = ActiveDesignFile.Levels(i)

           If lv.IsDisplayedInView(vw) Then

               sc.IncludeLevel lv

           End If

       Next i

    End Function

    Regards, Stefan.

  • Jon,

    Sorry I mistyped before.  I am using Matrix3dIdentity.

    Sub LabelIntersectionsofLines()

       Dim ScanCriteria    As New ElementScanCriteria

       Dim ScanEnumerator  As ElementEnumerator

       Dim ScanEnumerator2 As ElementEnumerator

       Dim MyElement       As Element

       Dim MyElement2      As Element

       Dim t               As Integer

       Dim i               As Integer

       Dim points()        As Point3d

       Dim point As Point3d

       i = -1

       ScanCriteria.ExcludeAllLevels

       ScanCriteria.IncludeLevel ActiveDesignFile.Levels("1Left_Coping")

       Set ScanEnumerator = ActiveModelReference.Scan(ScanCriteria)

       Set ScanEnumerator2 = ActiveModelReference.GetSelectedElements

    Do While ScanEnumerator.MoveNext

     Set MyElement = ScanEnumerator.Current

     Do While ScanEnumerator2.MoveNext

       Set MyElement2 = ScanEnumerator2.Current

       If MyElement.IsIntersectableElement Then

       points = MyElement.AsIntersectableElement.GetIntersectionPoints(MyElement2, Matrix3dIdentity)

       End If

       For t = 0 To UBound(points)

       MsgBox ("x:" & points(t).X & " " & "y:" & points(t).Y & " " & "z:" & points(t).Z)

          CadInputQueue.SendDataPoint points(t), 1

       Next

     Loop

    Loop

    End Sub

  • Stefan.  I cant figure out where this goes in my code.  Can you look at the code I pasted above and show me how this would work in my code

  • Stefan,

    I changed it to compare the current selection as both ElementEnumerators so it is effectively comparing against itself so I don't have to worry about the levels.  I can have the user select all the elements and then it will give them all the intersection points.

    Jon,

    I have figured out when it gives me the duplicate intersection points.  When a line has been extended to intersection of the other element then it will give me two intersection points but if I extend the line to where they are crossing each other not one element extended to the intersection then it will only give me one intersection point.  I don't know what is causing this but this is when the issues occurs.  Thanks for all your help.

  • Comment out your Line and put mine instead:

    'ScanCriteria.IncludeLevel ActiveDesignFile.Levels("1Left_Coping")

    AddVisibleLevelsToScanCriteria ScanCriteria, 0

    And you have to paste my function into your module of course.

    Regards, Stefan.

  • OK guys. I am still having issues with this VBA.  Here is the current code.  Now the problem I am having is when a level has more than 1 element on it then it will only process the first element.  Now I am comparing my selection set vs. the active level and it works fine as long as the active level has only one element.  If the active level has 2 or more elements then it will only find the intersection of my selection set vs the first element on the level.  PLEASE HELP!!!  THANKS!

    Sub LabelIntersections()

      Dim ScanCriteria    As New ElementScanCriteria

      Dim ScanEnumerator  As ElementEnumerator

      Dim ScanEnumerator2 As ElementEnumerator

      Dim MyElement       As Element

      Dim MyElement2      As Element

      Dim t               As Integer

      Dim i               As Integer

      Dim points()        As Point3d

      Dim point As Point3d

      i = -1

      ScanCriteria.ExcludeAllLevels

      ScanCriteria.IncludeLevel ActiveSettings.Level

      Set ScanEnumerator = ActiveModelReference.Scan(ScanCriteria)

      Set ScanEnumerator2 = ActiveModelReference.GetSelectedElements

    Do While ScanEnumerator.MoveNext

    Set MyElement = ScanEnumerator.Current

    Do While ScanEnumerator2.MoveNext

      Set MyElement2 = ScanEnumerator2.Current

      If MyElement.IsIntersectableElement Then

      points = MyElement.AsIntersectableElement.GetIntersectionPoints(MyElement2, Matrix3dIdentity)

      End If

      For t = 0 To UBound(points)

       'MsgBox ("x:" & points(t).X & " " & "y:" & points(t).Y & " " & "z:" & points(t).Z)

       CadInputQueue.SendDataPoint points(t), 1

      Next

    Loop

    Loop

       CadInputQueue.SendCommand "MDL SILENTLOAD CLEANUP"

       lngTemp = Not 15

       lngTemp = GetCExpressionValue("sdG.duplicatesAction", "CLEANUP") And lngTemp

       SetCExpressionValue "sdG.duplicatesAction", lngTemp Or 2, "CLEANUP"

       CadInputQueue.SendCommand "CLEANUP DO"

       CadInputQueue.SendCommand "DMSG UPDATEDIALOG -400"

       CadInputQueue.SendCommand "MDL UNLOAD CLEANUP"

       Set ScanEnumerator = Nothing

       Set ScanEnumerator2 = Nothing

    End Sub

  • Phillip:

    1)

    You should not process points if MyElement.IsIntersectableElement returns False.

    It should be like this:

      If MyElement.IsIntersectableElement Then
        points = MyElement.AsIntersectableElement.GetIntersectionPoints(MyElement2, Matrix3dIdentity)

        For t = 0 To UBound(points)
         CadInputQueue.SendDataPoint points(t), 1
        Next
      End If

    2)

    Calls:

    Set ScanEnumerator = Nothing
    Set ScanEnumerator2 = Nothing


    are in your case redundant.