Attribute VB_Name = "z_VsoGraph" ' ========= Extension functions for Visio ======== ' Shared module version: 20210414 ' Depends on: CDS_Graph ' Required reference: Scripting Option Private Module Option Explicit Public Enum TConnectorDirection T_CD_NONE = 0 T_CD_STRAIGHT = 1 T_CD_REVERSE = 2 T_CD_MUTUAL = 3 End Enum Public Type ItemConnector begin_ As Visio.Shape end_ As Visio.Shape dir_ As TConnectorDirection End Type Public Function ScanConnector(iArrow As Visio.Shape) As ItemConnector ScanConnector.dir_ = GetConnectorDirection(iArrow) If iArrow.Connects.Count = 2 Then Set ScanConnector.begin_ = iArrow.Connects(1).ToSheet Set ScanConnector.end_ = iArrow.Connects(2).ToSheet ElseIf iArrow.Connects.Count = 1 Then If iArrow.CellsU("BeginX").Formula Like "*GLUE*" Then Set ScanConnector.begin_ = iArrow.Connects(1).ToSheet Else Set ScanConnector.end_ = iArrow.Connects(1).ToSheet End If End If End Function Public Function ScanGraph(ByRef iSeed As Collection, bReverseLinks As Boolean) As CDS_Graph Dim iVisited As New Scripting.Dictionary Dim iGraph As New CDS_Graph Do While iSeed.Count > 0 Dim aShape As Visio.Shape: Set aShape = iSeed.Item(1) Call iSeed.Remove(1) If aShape.OneD Then _ GoTo NEXT_SHAPE Dim nShape&: nShape = aShape.ID If iVisited.Exists(nShape) Then _ GoTo NEXT_SHAPE Call iVisited.Add(nShape, 0) Call iGraph.AddNode(nShape) Call ScanConnectorsFor(aShape, iSeed, iGraph, bReverseLinks) NEXT_SHAPE: Loop Set ScanGraph = iGraph End Function Public Function VsoGetConnectedShape(vConnector As Visio.Shape, bBegin As Boolean) As Visio.Shape Dim iConnector As ItemConnector: iConnector = ScanConnector(vConnector) If bBegin Then Set VsoGetConnectedShape = IIf(iConnector.dir_ <> T_CD_REVERSE, iConnector.begin_, iConnector.end_) Else Set VsoGetConnectedShape = IIf(iConnector.dir_ <> T_CD_REVERSE, iConnector.end_, iConnector.begin_) End If End Function ' ===== Private Function IsArrow(nEndType&) As Boolean Select Case nEndType Case 1 To 8: IsArrow = True Case 12 To 19: IsArrow = True Case 39 To 40: IsArrow = True Case 43 To 45: IsArrow = True Case Else: IsArrow = False End Select End Function Private Function GetConnectorDirection(target As Visio.Shape) As TConnectorDirection Dim bBegin As Boolean: bBegin = IsArrow(target.CellsU("BeginArrow")) Dim bFinish As Boolean: bFinish = IsArrow(target.CellsU("EndArrow")) If bBegin Then GetConnectorDirection = IIf(bFinish, T_CD_MUTUAL, T_CD_REVERSE) Else GetConnectorDirection = IIf(bFinish, T_CD_STRAIGHT, T_CD_NONE) End If End Function Private Function ScanConnectorsFor(target As Visio.Shape, ByRef iSeed As Collection, ByRef iGraph As CDS_Graph, bReverseLinks As Boolean) Dim iConnect As Visio.Connect For Each iConnect In target.FromConnects If iConnect.FromSheet.Connects.Count <> 2 Then _ GoTo NEXT_CONNECT Dim theInfo As ItemConnector: theInfo = ScanConnector(iConnect.FromSheet) If bReverseLinks Then If theInfo.dir_ = T_CD_STRAIGHT Then theInfo.dir_ = T_CD_REVERSE ElseIf theInfo.dir_ = T_CD_REVERSE Then theInfo.dir_ = T_CD_STRAIGHT End If End If If GraphAddEdge(iGraph, theInfo, theInfo.begin_ = target) Then Dim destShape As Visio.Shape: Set destShape = IIf(theInfo.begin_ = target, theInfo.end_, theInfo.begin_) Call iSeed.Add(destShape) End If NEXT_CONNECT: Next iConnect End Function Private Function GraphAddEdge(ByRef graph As CDS_Graph, iConnector As ItemConnector, fixedBegin As Boolean) As Boolean GraphAddEdge = False Select Case iConnector.dir_ Case T_CD_MUTUAL, T_CD_NONE: Call graph.AddEdge(iConnector.begin_.ID, iConnector.end_.ID) Call graph.AddEdge(iConnector.end_.ID, iConnector.begin_.ID) GraphAddEdge = True Case T_CD_REVERSE: If Not fixedBegin Then Call graph.AddEdge(iConnector.end_.ID, iConnector.begin_.ID) GraphAddEdge = True End If Case T_CD_STRAIGHT: If fixedBegin Then Call graph.AddEdge(iConnector.begin_.ID, iConnector.end_.ID) GraphAddEdge = True End If End Select End Function