Quick way to reconnect many Shapes

Started by doudou, July 16, 2014, 04:45:00 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

doudou

Hello,

I am very new to Visio so I apologize in advance if my question is silly. I have a Visio 2010 diagram with many shapes created by my predecessor. There are many instance of shapes that "appear" to be connected but are not really connected: there is a connector between the shapes but when I select the connector I only see one bright green circle at the end of the connector instead of two (one at each end). I am guessing my predecessor did not extend the connector long enough for the shapes to connect. My question is, is there a quick way in Visio 2010 or 2013 to reconnect all the shapes that should have been connected without the need to go reconnect one pair at a time. Thanks in advance!

Jean

Yacine

#1
You'll either have to do the job by hand, or chose the wiser solution namely to accept the imperfection of your drawings.

A macro could probably do the job by checking the spatialneighborhood of the connectors, but I think this is beyond the capabilities of a visio beginner.
Yacine

doudou

Hi Yacine,

Thank you for reply. Although I have very limited knowledge of  Visio and its object model. I have a fair amount of experience with VBA in Excel and Outlook. I will  give Shape.SpatialNeighbors property a shot. I think i will basically loop through all shapes on the page, look for connectors in close vicinity, check if they are connected, if not connect them. Thanks again

Jean

Yacine

#3
Bonne chance, je reste à ta disposition ;-)

PS: just an idea, but if the neighborhood of the whole connector does not work, may be a temporarly placed shape at the end of connector may give more precise data.

Second thought, you may want to connect the connector not the whole shape, but to its shape handles, in order to avoid too much re-routing. Recording an according macro shall give you the right commands.
Yacine

wapperdude

Another possibility, assuming that the un-connected ends are either on or very close to the desired shape would be to simply go thru and wiggle each shape by a teeny bit.  That ought to be enough to get the connector to glue.  Final spot of each shape would be its starting position.

Might work.

Wapperdude.
Visio 2019 Pro

Yacine

@Wayne, "... and wiggle each shape by a teeny bit..." by hand or otherwise? Didn't really get your idea.
Yacine

wapperdude

By code...so each shape gets moved a small amount +/1 x-direction, +/- y-direction. 

The assumption is that all of these disconnected ends are either on top of the shape's connection point, but not glued, or all are consistently away from the shape by a small amount.  Each shape is moved to allow the offset connection point to glue to the shape, and shape returned.  Or, if connector and connection point overlap, but are not glued, then, returning the shape to that spot will activate the gluing mechanism.  For shapes already glued, no harm done. 

Seemed like it might be easier than to search the neighborhood, try to find who's disconnected and then take steps to connect.  Not saying it'll work.  But, it might be easier.  Ought to be easy to write a small loop to nudge the shape around by a specific amount.

Clearly not elegant, and if there's no consistency, might not work.  But, if there is consistency, could be simple, quick approach.

Wapperdude
Visio 2019 Pro

doudou

@ Wapperdude. Thanks for your suggestion. It is actually pretty elegant and would have worked perfect for my situation. However it appears that the "Selection.Move" method does not behave the same way as mouse click-hold move action. In the sense that the snapping of a connector to a shape appears to be a mouse-click event and not triggered by "moving" of shapes. We can also confirm this by selecting a connector and moving it with the keyboard arrows. I have actually the VBA code shown below. It appears to work for small test cases, but I I am getting some really weird stuff when I try it on the real file.

Sub FixConnections()

    Dim viShapes As Visio.Shapes
    Set viShapes = ActivePage.Shapes
    Dim myShape As Visio.Shape, con As Visio.Shape
    Dim neighbor As Visio.Selection
    Dim vsoCell1 As Visio.Cell
    Dim vsoCell2 As Visio.Cell
   
   
    For Each myShape In viShapes
        If Not myShape.CellExists("EndX", 0) Then
            Set neighbor = myShape.SpatialNeighbors(8, 0.025, 0)
            For Each con In neighbor
                If con.CellExists("EndX", 0) Then
                    If con.Cells("BeginX").result(visInches) > myShape.Cells("PinX").result(visInches) Then
                        Set vsoCell1 = Application.ActiveWindow.Page.Shapes.ItemFromID(con.ID).CellsU("BeginX")
                        Set vsoCell2 = Application.ActiveWindow.Page.Shapes.ItemFromID(myShape.ID).CellsSRC(7, 1, 0)
                        If Not CheckConnected(myShape, con) Then
                            vsoCell1.GlueTo vsoCell2
                        End If
                    ElseIf con.Cells("EndX").result(visInches) < myShape.Cells("PinX").result(visInches) Then
                        Set vsoCell1 = Application.ActiveWindow.Page.Shapes.ItemFromID(con.ID).CellsU("EndX")
                        Set vsoCell2 = Application.ActiveWindow.Page.Shapes.ItemFromID(myShape.ID).CellsSRC(7, 0, 0)
                        If Not CheckConnected(myShape, con) Then
                            vsoCell1.GlueTo vsoCell2
                        End If
                    End If
                End If
            Next
        End If
    Next
End Sub

Function CheckConnected(myShape As Visio.Shape, con As Visio.Shape) As Boolean
    Dim IDs() As Long
    IDs = myShape.ConnectedShapes(visConnectedShapesAllNodes, "")
    Dim i As Long
    CheckConnected = False
    For i = 0 To UBound(IDs, 1)
        If IDs(i) = con.ID Then
            CheckConnected = True
            Exit For
        End If
    Next i
End Function

wapperdude

The code appears to be OK.  Not my forte.  However, it appears that you could simplify the code a little, perhaps that'll help with some of problems you're having on the full up version.

1.)  The "IFs" checking for connectivity don't seem to be necessary.  Execution is fast, and if already connected, who cares? 
2.)  Once you eliminate the "IFs", then you can eliminate CheckConnected code.

Of course, not seeing your complete drawing, I could be overlooking something, but, the code will only apply to the selected connector and shape as dictated by the SRC description.

Anyway, nice work so far.  Looks like you were able to put the code together fairly quickly.

Wapperdude

Visio 2019 Pro

Yacine

Hi Jean,
I played a little bit with your code.
I changed the cell to connect to to (1,1,0)
I increased the tolerance of the spatialneighbors
and it seems to work

(had to write my own connectedshapes function though, cause I'm still on V2007.
Yacine

AndyW

Wiggling the shape only works if done manually, not by automation.
Live life with an open mind

doudou

@Yacine. c'est gentil de ta part d'avoir pris le temps de m'aider! Merci bien!

In English:   ;D

Changing the cell to connect to to (1,1,0) seems to work on the real diagram!. Although in some way the connectors shape changed.  I think the best way would be to have the connector glue to the closest shape handle instead of a fixed cell. I am not sure if this is possible with Visio though (please be patient with me, first time I used Visio was 8 days ago!)

wapperdude

#12
The difference in approaches is that the (1,1,0) invokes the "walking glue" method.  That means as the shape is moved, Visio will decide where it glues to the shape.  This could be a problem if you always wanted a specific location.  It also explains why the connector shape changes...it's gluing to a different spot.

The (7,1,0) approach glues to a specific connector point.  The 2nd number tells which connector point to use.  Not having seen your document, your code always uses either the 1st or 2nd row, i.e., "0" or "1".  If the shape has additional connection points, and one or more of them is the desired, then, it is necessary to change the row entry value.  This is a limitation of using specific connection points.  This complicates the problem, because now you have to determine which connector should go to which connection point.  I suspect that the neighborhood needs to be small enough to only surround a given connection point on a shape, but large enough to capture the connector floating end.  That should allow unique identities for both connector shape ID, and the specific connection point row.  Thus, the code would have to step thru each connection point on a shape, verify if it's not connected, find the nearest connector, and then glue the two together.

HTH
Wapperdude
Visio 2019 Pro

doudou

@wapperdude, "Thus, the code would have to step thru each connection point on a shape, verify if it's not connected, find the nearest connector, and then glue the two together." Can you please post a snippet that I could use. I think this the solution to the problem. Thanks!

wapperdude

#14
Like Yacine, I only have V2007.  Unlike Yacine, my programming is not that strong, but, I think you have most of the pieces.

You need to iterate thru each shape that is not a connector. 
    For each shape, you need to go thru each connection point.
       Set a variable for number of rows and then step thru.  E.g.
           nrows = shp.RowCount(visSectionConnectionPts)
           For j = 0 To nrows - 1

               Add code to grab X, Y positions of connection point
               translate positions to page coordinates
               use those coordinates for neighbhood search for connector
               check connectivity
                    if not, then use shape IDs, and row index "j" to glue connector to connection point.
          next row.
      next shape

HTH
You'll probably do this faster than I could.
Wapperdude
Visio 2019 Pro