[CONNECT VBA] Clip inside fence

Hi!

I have a DGN file with many elements (lines, linestrings, shapes, sharedcells, etc.).

I make a fence from an shape element. I have these elements in the array in the program and they are drawn in the model.

If I use a tool for fence, then everything works fine.

Then I wrote a small macro to do this automatically. But the result of his work is different.

    For i = LBound(Segments) To UBound(Segments)
        Dim oFence As Fence
        Dim oFenceContents As ElementEnumerator
        
        ActiveSettings.FenceVoid = False
        ActiveSettings.FenceOverlap = False
        ActiveSettings.FenceClip = True
        
        Set oFence = ActiveModelReference.Attachments(Index).DesignFile.Fence   ' This attached file has elements for clip
        oFence.DefineFromModelPoints TopView, Segments(i).Points                ' This shape's vertices

        Set oFenceContents = oFence.GetContents
        
        While oFenceContents.MoveNext
            Dim curEle As Element
            Set curEle = oFenceContents.Current.Clone   ' if without clone - error "Invalid cell"
            curEle.Color = 3
            curEle.LineWeight = 1

            ActiveModelReference.AddElement curEle
            Set curEle.Level = ActiveModelReference.Levels.FindByNumber(0)
        Wend
    Next i

What could be the problem?

  • Unknown said:
    What could be the problem?

    It's hard to say without some evidence: screenshots are good, DGN files are better.  Post the DGN file with the model where the clipping is not what you expect.

    What is variable Segments?

     
    Regards, Jon Summers
    LA Solutions

  • Segments - it's array of my structure for programm.

    Segments(i).Points - These are the vertices of the shape.

    DGN File: https://yadi.sk/d/bw2QMLZ03LcDEi

    In the Fences layer (50) there are shapes for work.

    But once again I will say: the manual tool works well.

    For a simple test, I wrote a small procedure.

    It creates a fence from the selected shape-element. The View is set to View number 1 (Top).

    Sub TestFence()
        Dim fenceEnum  As ElementEnumerator
        Set fenceEnum = ActiveModelReference.GetSelectedElements
    
        While fenceEnum.MoveNext
            Dim oFence As Fence
            Dim oFenceContents As ElementEnumerator
            
            ActiveSettings.FenceVoid = False
            ActiveSettings.FenceOverlap = False
            ActiveSettings.FenceClip = True
            
            Set oFence = ActiveDesignFile.Fence
            oFence.DefineFromElement ActiveDesignFile.Views(1), fenceEnum.Current
    
            Set oFenceContents = oFence.GetContents
            
            While oFenceContents.MoveNext
                Dim curEle As Element
                Set curEle = oFenceContents.Current.Clone
                curEle.Color = 3
                curEle.LineWeight = 1
    
                ActiveModelReference.AddElement curEle
            Wend
        Wend
    End Sub

  • Unknown said:
    For a simple test, I wrote a small procedure

    That code is different to the first example you posted.  Does that second example fail in the same way?

     
    Regards, Jon Summers
    LA Solutions

  • The only difference is that the new code does not need data that the entire program calculates. In the attached file, the fences are exactly those that the program creates. The connected file is also not used, because I gave the source file myself.
    The result using this procedure is similar - there are errors in the form of missing parts of the elements.

  • The example DGN has a reference For fence.dgn.  You haven't supplied that so I can't  tell what's in it.

    You can't clip anything in a reference attachment.

    I can make MicroStation's manual fence tools misbehave (in V8i SS3).  See the screenshot below.  I created a fence from your red shape on level Fence, then did element move using the fence.  The move correctly worked on elements within the fence, but look at your neighbouring green shape also on level Fence: it's been cut by the fence move operation even though it lies outside the fence.

    So something is wrong, before you even start using VBA!

     
    Regards, Jon Summers
    LA Solutions

  • Hi Maxim,

    Unknown said:
    What could be the problem?

    I see two problems there:

    • You make a clonning yourself, which is think is not the right way. If you want to be close to MicroStation tools, in my opinion you should allow fence to clone elements for you in this case.
    • The design file is (internally) ugly. I assume it comes from AutoCAD, so cells are shared with weird structure. When tested in V8i, it's even not possible to drop them correctly, because some parts simply dismiss. In CONNECT Edition it seems it works better.

    This code seems to work, but I had not enough time for any more extensive testing:

    Option Explicit
    
    Public Sub ProcessFence()
    
        Dim fenceElement As ClosedElement
        Set fenceElement = ActiveModelReference.GetElementByID(DLongFromLong(879920))
    
        CadInputQueue.SendKeyin "view top;selview 1"
    
        Dim viewWithFence As View
        Set viewWithFence = ActiveDesignFile.Views(1)
    
        Dim fnc As Fence
        ActiveDesignFile.Fence.DefineFromElement viewWithFence, fenceElement
        
        ActiveSettings.FenceVoid = False
        ActiveSettings.FenceClip = True
        
        Dim ee As ElementEnumerator
        Set ee = ActiveDesignFile.Fence.GetContents(True, True)
        
        Dim targetLevel As Level
        Set targetLevel = ActiveDesignFile.Levels("elems from fence")
        
        Do While ee.MoveNext
            ee.Current.Level = targetLevel
            ActiveModelReference.AddElement ee.Current
        Loop
        
        ActiveDesignFile.Fence.Undefine
    End Sub

    For a simplicity I created a new level "elems from fence" and to move all processed elements from fence to this level, so the rest of file is not changed. A content of this level looks correctly and as expected. But as I wrote, no detail evaluation was done.

    With regards,

      Jan

  • Hi Jan,

    Thanks for your code! I was looking for it. 

    But I would like to "redecorate" it in 6th line - so I don't want to indicate fenceElement by ID but by Level <name> AND msdElementType ellipse.

    And stops at error

    Option Explicit
    
    Public Sub ProcessFence()
    
        Dim fenceElement As ClosedElement
        
        Dim oScanCriteria As ElementScanCriteria
        Set oScanCriteria = New ElementScanCriteria
        Dim oLevel As Level
        Set oLevel = ActiveDesignFile.Levels("elem")
        oScanCriteria.ExcludeAllLevels
        oScanCriteria.IncludeLevel oLevel
        Dim oScanEnumerator As ElementEnumerator
        Set oScanEnumerator = ActiveModelReference.Scan(oScanCriteria)
    
       
        Set fenceElement = ActiveModelReference.Scan(oScanCriteria)
    
        CadInputQueue.SendKeyin "view top;selview 1"
    
        Dim viewWithFence As View
        Set viewWithFence = ActiveDesignFile.Views(1)
    
        Dim fnc As Fence
        ActiveDesignFile.Fence.DefineFromElement viewWithFence, fenceElement
        
        ActiveSettings.FenceVoid = False
        ActiveSettings.FenceClip = True
        
        Dim ee As ElementEnumerator
        Set ee = ActiveDesignFile.Fence.GetContents(True, True)
        
        Dim targetLevel As Level
        Set targetLevel = ActiveDesignFile.Levels("elems from fence")
        
        Do While ee.MoveNext
            ee.Current.Level = targetLevel
            ActiveModelReference.AddElement ee.Current
        Loop
        
        ActiveDesignFile.Fence.Undefine
    End Sub

    Could I ask you for some advice?

    Regards

    Paweł

  • I would like to "redecorate" it in 6th line

    It's not clear what you mean.  Line 6 is empty. 

    I want to indicate fenceElement by Level <name> AND msdElementType ellipse

    Something like this?

    Dim oScanCriteria As ElementScanCriteria
    Set oScanCriteria = New ElementScanCriteria
    SetScanCriteriaForLevelAndElemType oScanCriteria, "my level", msdElementTypeEllipse
    Set oScanEnumerator = ActiveModelReference.Scan(oScanCriteria)

    Subroutine SetScanCriteriaForLevelAndElemType is a small procedure having a single purpose — to set up your scan criteria

    Sub SetScanCriteriaForLevelAndElemType ( _
        ByVal oCriteria As ElementScanCriteria, _
        ByVal levelName As String, _
        ByVal elemType As MsdElementType)
      With oCriteria
        '  Set level
        Dim oLevel As Level
        Set oLevel = ActiveDesignFile.Levels(levelName)
        .ExcludeAllLevels
        .IncludeLevel oLevel  
        '  Set element type
        .ExcludeAllTypes
        .IncludeType elemType
      End With
    End Sub

     
    Regards, Jon Summers
    LA Solutions

  • Hi Jon,

    6th line of Jan's code not mine Slight smile

    Thank you for your reply.

    So  I implemented your remarks and code looks like this:

    Option Explicit
    
    Public Sub ProcessFence()
    
        Dim fenceElement As ClosedElement
       
        Dim oScanCriteria As ElementScanCriteria
        Dim oScanEnumerator As ElementEnumerator
        Set oScanCriteria = New ElementScanCriteria
        SetScanCriteriaForLevelAndElemType oScanCriteria, "elem", msdElementTypeEllipse
        Set oScanEnumerator = ActiveModelReference.Scan(oScanCriteria)
        Set fenceElement = ActiveModelReference.Scan(oScanCriteria)
        CadInputQueue.SendKeyin "view top;selview 1"
        Dim viewWithFence As View
        Set viewWithFence = ActiveDesignFile.Views(1)
    
        Dim fnc As Fence
        ActiveDesignFile.Fence.DefineFromElement viewWithFence, fenceElement
        
        ActiveSettings.FenceVoid = False
        ActiveSettings.FenceClip = True
        
        Dim ee As ElementEnumerator
        Set ee = ActiveDesignFile.Fence.GetContents(True, True)
        
        Dim targetLevel As Level
        Set targetLevel = ActiveDesignFile.Levels("elems from fence")
        
        Do While ee.MoveNext
            ee.Current.Level = targetLevel
            ActiveModelReference.AddElement ee.Current
        Loop
        
        ActiveDesignFile.Fence.Undefine
    End Sub
    Sub SetScanCriteriaForLevelAndElemType( _
        ByVal oCriteria As ElementScanCriteria, _
        ByVal levelName As String, _
        ByVal elemType As MsdElementType)
      With oCriteria
        '  Set level
        Dim oLevel As Level
        Set oLevel = ActiveDesignFile.Levels(levelName)
        .ExcludeAllLevels
        .IncludeLevel oLevel
        '  Set element type
        .ExcludeAllTypes
        .IncludeType elemType
      End With
    End Sub

    Now I got problem with line: "Set fenceElement = ActiveModelReference.Scan(oScanCriteria)"

    fenceElement is a closedElement not ElementEnumerator

    Error 13 mismatch.

    Unfortunately, I cannot load help content.

    May I ask politely for help ith it?

    Regards,

    Paweł

  • I got problem with line: "Set fenceElement = ActiveModelReference.Scan(oScanCriteria)"

    That should be

    Set oScanEnumerator = ActiveModelReference.Scan (oScanCriteria)
    I cannot load help content


    VBA Help
    VBA help

     
    Regards, Jon Summers
    LA Solutions