Visio Guy

Visio Discussions => ShapeSheet & Smart Shapes => Topic started by: The Walrus on October 16, 2017, 07:08:17 PM

Title: Stretch Smart Shape & automatically add connection points [SOLVED]
Post by: The Walrus on October 16, 2017, 07:08:17 PM
Hello,

I'm a relative Visio newbie, thrust into the environment for reasons of cost savings.  Overall, I'm making the transition fairly well but, like any good engineer my ultimate goal is to become really, really lazy.  To that end, I'll expend great amounts of effort to get there!

We are currently using Visio13 for electrical system schematics.  90% or greater of our drawings are for interconnections black boxes together with wires and cables.  The Powers-that-Be have determined that our previous CAD package was too expensive to maintain, and that Visio would suit our needs at a fraction of the cost.  Mostly, they are correct.

Now to the crux of my problem.

In our drawings, we are often having to resize shapes (i.e. electrical connectors). The default behavior in Visio tends to be that the connection points move based on proportion of the shape rather than on grid or with defined spacing.

I would like to build/create a smart shape that started off as two pins, but that the user can stretch or collapse as required in their drawing, while automatically inserting/removing connection points corresponding to the grid.  I've attached a sheet to hopefully demonstrate more precisely the desired effect.

This thread (http://visguy.com/vgforum/index.php?topic=8087.0) seems to maybe cover the collapsing behavior to some extent, but I'm not sure that's the right approach for what I need.

Any help would be greatly appreciated!
Title: Re: Stretch Smart Shape & preserve properties & automagically add connection points
Post by: wapperdude on October 16, 2017, 11:14:54 PM
Here are some things to help you on your way...
http://visguy.com/vgforum/index.php?topic=6314.msg31942#msg31942 (http://visguy.com/vgforum/index.php?topic=6314.msg31942#msg31942)

See attached for "expanding/contracting" shapes.

Wapperdude

Title: Re: Stretch Smart Shape & preserve properties & automagically add connection points
Post by: The Walrus on November 02, 2017, 05:33:15 PM
I have spent an awful lot of time not getting very far.  I think my trouble is truly understanding how the properties in teh shape sheets interact.

So, perhaps I need to back off a bit and start more simply.

Looking at the VSD in my OP, I think I'd just like to start simply with being able to stretch a shape and have it preserve some certain dimensions.  See C & D in that VSD.

I'll then build from there.

Are there any decent tutorials somewhere that are specific to just being able to create a 'stretchable' shape that preserves certain dimensions?  Like maybe with an arrow that preserves the size and ratios of the arrow head when stretched?
Title: Re: Stretch Smart Shape & preserve properties & automagically add connection points
Post by: wapperdude on November 04, 2017, 12:33:59 AM
Sorry about the confusion.  Attached is a simpler shape.  This demonstrates the basics of stretching a shape between some minimum value and maximum value in discrete steps using the bound function.  As the shape expands or contracts, connection points are "added" or removed" as is appropriate.  Note, no connection points are eliminated, the unused ones are merely stacked on top of each other.  It would require code to reduce or increase the number of connection points as that would require eliminating or adding lines to the Connection point section of the shapesheet.

HTH

Wapperdude
Title: Re: Stretch Smart Shape & preserve properties & automagically add connection points
Post by: wapperdude on November 04, 2017, 06:33:49 PM
Here's another version, this uses a fixed list to choose the number of connection points.  Dbl click the shape to bring up the shapedata, select the number of connection points, and enter the desired pin to pin spacing.  The shape will automatically size based upon those settings.

Wapperdude
Title: Re: Stretch Smart Shape & preserve properties & automagically add connection points
Post by: The Walrus on April 12, 2018, 03:47:58 PM
I'm back, and I've not been able to accomplish any of my desired traits in this thread.  So I'm going to back way off to baby steps.

Step 1.

I would like to build a shape in Visio, and when I stretch it or contact it, I want both ends of the shape to maintain their dimensions.  At this point I am not at all worried about connection points.  I just want the shape to act as a 'smart shape' as in this article (http://www.visguy.com/2009/07/22/why-visio-shape-smarts-makes-your-life-easier/).  I can stretch the arrow as much as I want, but the arrow head itself stays the same.  I want to learn how to create this functionality for my shapes (that aren't arrows).

What properties allow me to do this?  Where in the ShapeSheet or elsewhere do I need to go to make this happen?  The Shape Design --> Behavior or Shape Design --> Protection dialogs seem like they should be helpful, but they are not.

I tried using the arrow stencil from General --> Blocks, and opening the ShapeSheet, but I can't seem to find anything that 'locks' the arrowhead dimensions in place.

Please help!
Title: Re: Stretch Smart Shape & preserve properties & automagically add connection points
Post by: Yacine on April 12, 2018, 04:14:25 PM
Would this help: http://visguy.com/vgforum/index.php?topic=7120.0 ?
Title: Re: Stretch Smart Shape & preserve properties & automagically add connection points
Post by: wapperdude on April 12, 2018, 06:01:55 PM
Wrt shape stretching, this article directly covers the topic:  https://msdn.microsoft.com/en-us/library/aa200966(v=office.10).aspx (https://msdn.microsoft.com/en-us/library/aa200966(v=office.10).aspx).  It is part of a very comprehensive discussion based upon V2002.  Everything in this entire article, some 28 chapters, is excellent foundational information.

Enjoy!
Wapperdude
Title: Re: Stretch Smart Shape & preserve properties & automagically add connection points
Post by: The Walrus on April 12, 2018, 08:13:16 PM
Yes, both of these posts are VERY helpful!
Title: Re: Stretch Smart Shape & preserve properties & automagically add connection points
Post by: The Walrus on April 14, 2018, 08:30:01 PM
So, thanks to the posts on the 12th, I have made some great progress!  I have been able to use the Geometry section to create a smart shape with the behavior I would like.

Now, on to the connection points.  I've attached a vsd with the shape I've created, and I've added a few connection points that behave as I would like.

Now, I'm looking to add the connection points automatically.

I'm fairly adept at writing excel functions, and it seems that Visio uses a lot of the same functions, but even more.

I'm thinking there ought to be a way to add connection points automatically based on a function of the height.  Perhaps test for height, and divide by distance, and the result is N.  For every N, place a connection point.  Am I barking up the right tree?

Take a peek at what I have so far and feel free to critique.
Title: Re: Stretch Smart Shape & preserve properties & automagically add connection points
Post by: The Walrus on April 23, 2018, 06:31:10 PM
I'm getting very much closer, but it appears that I need to run a Macro to get the connection points to work properly.  I haven't written code in ages, and I'm not sure how to call aspects of the shape sheet into Visual Basic, so I would appreciate any help in that arena.  I think my logic is right, or at least right enough to get where I want to go, but syntax is where I'm stuck.

Sub AddConnPts()

Dim I As Integer    'Incrementer
Dim N As Integer    'Number of Connection Points Needed
Dim C As Integer    'Number of existing Connection Points
Dim H As Long       'Height of Shape
Dim HString As String   'String to put in Connect points Y Column
Dim WString As String  'String to put in Connect points X Column

Get Shape NameID            'Don't know how to do this
    Get shape Height = H    'How to get height off shapesheet for NameID
        If H > 0.5 Then
            N = (H - 0.25) / 0.125           'Sets number of needed connection points based on geometry of shape
            Get Existing Connection Points = C  'How to count the number of existing connection points on NameID
            If C < N Then
                For I = C + 1 To N
           
                HString = "IF(Height*1>=0.5,Height*1-0.125*" &I ",0"   'how do I put this in the Connection Points area of Shape Sheet?
                WString = "Width*1"
               
                'How to insert strings in next incremented row of Connection Points section of shape sheet?
           
                Next I
            End If
        End If

End Sub

My intention is to add an Actions section into the part shape sheet and create an "Add Connections" Menu option for the shape that would then run the macro.

Any and all help is greatly appreciated!
Title: Re: Stretch Smart Shape & preserve properties & automagically add connection points
Post by: Yacine on April 25, 2018, 05:51:02 AM
Hi Walrus,
I had a look at your request and started working out a solution, for what you exactly asked for, then I understood that you were not that much after the macro itself, but rather the final shape (scaling as needed and moving its connection points) and finally I recalled having seen these exact shapes in an old topic.
Have a look at it: http://visguy.com/vgforum/index.php?topic=6271.15
It probably doesn't follow exactly your strategy, but I remember that Rudy was happy with his final result.
HTH, Y.
Title: Re: Stretch Smart Shape & preserve properties & automagically add connection points
Post by: The Walrus on April 25, 2018, 01:44:23 PM
Thanks, Yacine.

I looked at the implementation you linked, and while similar, that direction won't really work for our implementation.  I also wonder about the efficiency of them in larger drawing packages.  I've noticed that the larger a multi-page drawing is, the more Visio behaves...slowly.  So I wonder if huge, complicated shape sheets attached to every shape would affect performance?

I've also decided to go the macro direction for portability.  It seems to me that I should be able to write one macro to perform the necessary connection point automation across multiple shapes.

It's also now become...personal.  I want to conquer this.

In my research over the past few days, I've found two links that appear to give me the tools I need to conquer this issue.  One is yours, driven by the link above I got to this one (http://visguy.com/vgforum/index.php?topic=5802.msg23255#msg23255), which solves my problem of how to apply the macro to any selected shape.

The other is an MSDN article (https://msdn.microsoft.com/en-us/vba/visio-vba/articles/shape-cells-property-visio) that helps me add cells to the shape sheet and populate those cells.  This is also the link that makes me believe I can use a generic macro across multiple shapes.

If I am uninterrupted today, I believe I can have a working model today that should provide the functionality I want.  It might need tweaking, but I think I can get there from here.
Title: Re: Stretch Smart Shape & preserve properties & automagically add connection points
Post by: The Walrus on April 25, 2018, 09:42:33 PM
So, I didn't have long to work on this today and I'm making progress, but my code is behaving funny.
Sub AddCnPts()
'
' Automatically Add Connection Points
'
    Dim UndoScopeID2 As Long
    UndoScopeID2 = Application.BeginUndoScope("Add Connect")
    Dim intRowIndex1 As Integer
    intRowIndex1 = ActiveWindow.Selection(1).AddRow(visSectionConnectionPts, visRowLast, visTagCnnctPt)
    Dim vsoRow1 As Visio.Row
    Dim vsoCell As Visio.Cell
    Dim vsoShape As Visio.Shape
    Dim strHRow As String
    Dim shpHgt As Long
    Dim intI As Integer
   
    Set vsoShape = ActiveWindow.Selection(1)
    Set vsoCell = vsoShape.CellsU("Height")
    shpHgt = vsoCell
    If shpHgt >= 0.5 Then
            intI = (shpHgt - 0.25) / 0.125           'Sets number of needed connection points based on geometry of shape
    End If
   
    strHRow = "=IF(Height*1>=0.5,Height*1-(0.125*" & intI & "),0)"
   
    Set vsoRow1 = ActiveWindow.Selection(1).Section(visSectionConnectionPts).Row(intRowIndex1)
    vsoRow1.Cell(visCnnctX).FormulaU = "Width*1"
    vsoRow1.Cell(visCnnctY).FormulaU = strHRow
    vsoRow1.Cell(visCnnctDirX).FormulaU = -1#
    vsoRow1.Cell(visCnnctDirY).FormulaU = 0#
    vsoRow1.Cell(visCnnctType).FormulaU = visCnnctTypeInward
    Application.EndUndoScope UndoScopeID2, True
   
End Sub

This is just a starting point to make sure I can access individual cells and actually write the connection point data.  That stuff works.

However, when I set a breakpoint at End Sub so I can look at the variables, I find that vsoCell has the correct value, but shpHgt does not, and neither does intI.  I can't for the life of me figure why shpHgt = vsoCell doesn't actually set the value of vsoCell into the shpHgt variable.  Likewise, intI likes to default to "6".

So this is a learning process, and I don't believe I have ever done anything object-oriented in my life so this is new to me as well.
Title: Re: Stretch Smart Shape & preserve properties & automagically add connection points
Post by: Yacine on April 26, 2018, 07:54:43 AM
vsoCell is an object. Whilst VBA often converts correctly, in this case it seems to not having been able to.
But you don't need to introduce this intermediate variable, you can get directly the cell value as shown below.

Sub AddCnPts()
'
' Automatically Add Connection Points
'
    Dim UndoScopeID2 As Long
    Dim intRowIndex1 As Integer
    Dim vsoRow1 As Visio.Row
    'Dim vsoCell As Visio.Cell *** not needed
    Dim vsoShape As Visio.Shape
    Dim strHRow As String
    Dim shpHgt As Long
    Dim intI As Integer
   
    UndoScopeID2 = Application.BeginUndoScope("Add Connect")
    intRowIndex1 = ActiveWindow.Selection(1).AddRow(visSectionConnectionPts, visRowLast, visTagCnnctPt)
   
    If ActiveWindow.Selection.Count <> 1 Then
        MsgBox "This macro works with exactly ONE shape. Please select one and run again.", vbOK
        Exit Sub
    End If
   
    Set vsoShape = ActiveWindow.Selection(1)
    ' Set vsoCell = vsoShape.CellsU("Height")
    ' shpHgt = vsoCell
    shpHgt = vsoShape.Cells("Height").ResultIU
    If shpHgt >= 0.5 Then
            intI = (shpHgt - 0.25) / 0.125           'Sets number of needed connection points based on geometry of shape
    End If
   
    strHRow = "=IF(Height*1>=0.5,Height*1-(0.125*" & intI & "),0)"
   
    Set vsoRow1 = vsoShape.Section(visSectionConnectionPts).Row(intRowIndex1)
    With vsoRow1
        .Cell(visCnnctX).FormulaU = "Width*1"
        .Cell(visCnnctY).FormulaU = strHRow
        .Cell(visCnnctDirX).FormulaU = -1#
        .Cell(visCnnctDirY).FormulaU = 0#
        .Cell(visCnnctType).FormulaU = visCnnctTypeInward
    End With
   
    Application.EndUndoScope UndoScopeID2, True
   
End Sub
Title: Re: Stretch Smart Shape & preserve properties & automagically add connection points
Post by: The Walrus on April 26, 2018, 01:24:55 PM
Thanks for the feedback.  I'm still seeing the same behavior, though.

intI = 0
    shpHgt = 0
    shpHgt = vsoShape.Cells("Height").ResultIU
    If shpHgt >= 0.5 Then
            intI = (shpHgt - 0.25) / 0.125           'Sets number of needed connection points based on geometry of shape
    End If


If I put a breakpoint at the shpHgt = vsoShape.Cells("Height").ResultIU line, it shows intI and shpHgt as both = 0, and .ResultIU returns the correct value.

However a breakpoint at the beginning of the If statement returns shpHgt = 1, and a breakpoint at End If shows intI = 6.

Both variables are Long at this point.  So confused!
Title: Re: Stretch Smart Shape & preserve properties & automagically add connection points
Post by: The Walrus on April 26, 2018, 04:53:33 PM
Based on this MSDN link (https://msdn.microsoft.com/en-us/VBA/Visio-VBA/articles/cell-resultiu-property-visio), I changed the shpHgt variable to Double, and now both it and the intI are working.  How odd that changing the type of one variable affects the performance of another.
Title: Re: Stretch Smart Shape & preserve properties & automagically add connection points
Post by: The Walrus on April 26, 2018, 08:02:22 PM
I got it working!!!!

Sorry for the multiple posts today.

Here's my 'completed' code.  I'm sure I can optimize it further.

Sub AddConnPts()

    Dim I As Integer            'Incrementer
    Dim N As Integer            'Number of Connection Points Needed
    Dim C As Integer            'Number of existing Connection Points
    Dim H As Double             'Height of Shape
    Dim intRowIndex1 As Integer 'Row Incrementer
    Dim WString As String       'String to put in Connect points X Column
    Dim HString As String       'String to put in Connect points Y Column
    Dim vsoShape As Visio.Shape
    Dim vsoRow1 As Visio.Row
   
    If ActiveWindow.Selection.Count <> 1 Then
        MsgBox "This macro works with exactly ONE shape. Please select one and run again.", vbOK
        Exit Sub
    End If
   
    Set vsoShape = ActiveWindow.Selection(1)
    H = vsoShape.Cells("Height").ResultIU
   
    If H >= 0.5 Then
            N = ((H - 0.25) / 0.125)    'Sets number of needed connection points based on geometry of shape
       
            'Get Existing Connection Points = C
            C = ActiveWindow.Selection(1).RowCount(Visio.visSectionConnectionPts)
           
            'Loop through all the rows
            For intRowIndex1 = 0 To C - 1
            Next intRowIndex1
           
                If C < N Then
                    For I = C + 1 To N
           
                    intRowIndex1 = ActiveWindow.Selection(1).AddRow(visSectionConnectionPts, visRowLast, visTagCnnctPt)
                    WString = "Width*1"
                    HString = "IF(Height*1> 0.4375 + 0.125*" & intRowIndex1 - 1 & " ,Height*1-(0.125*" & I & "),0)"
                   
                    Set vsoRow1 = ActiveWindow.Selection(1).Section(visSectionConnectionPts).Row(intRowIndex1)
                    vsoRow1.Cell(visCnnctX).FormulaU = WString
                    vsoRow1.Cell(visCnnctY).FormulaU = HString
                    vsoRow1.Cell(visCnnctDirX).FormulaU = -1#
                    vsoRow1.Cell(visCnnctDirY).FormulaU = 0#
                    vsoRow1.Cell(visCnnctType).FormulaU = visCnnctTypeInward
           
                    Next I
                End If
        End If
   
End Sub
Title: Re: Stretch Smart Shape & preserve properties & automagically add connection points
Post by: The Walrus on April 30, 2018, 04:50:25 PM
I've played with it a bit more and have a final solution that works with all of my desired connector shapes.  I've attached a VSD file with them, and the 'final' code below.  I'll edit the thread also to indicate that this issue is solved. Thanks for all the help!

Sub AddConnPts()

    Dim I As Integer            'Incrementer
    Dim N As Integer            'Number of Connection Points Needed
    Dim C As Integer            'Number of existing Connection Points
    Dim H As Double             'Height of Shape
    Dim G As Double             'Geometry constant from Scratch section
    Dim intRowIndex1 As Integer 'Row Incrementer
    Dim WString As String       'String to put in Connect points X Column
    Dim HString As String       'String to put in Connect points Y Column
    Dim vsoShape As Visio.Shape
    Dim vsoRow1 As Visio.Row
   
    If ActiveWindow.Selection.Count <> 1 Then
        MsgBox "This macro works with exactly ONE shape. Please select one and run again.", vbOK
        Exit Sub
    End If
   
    Set vsoShape = ActiveWindow.Selection(1)
    H = vsoShape.Cells("Height").ResultIU
    G = vsoShape.Cells("Scratch.Y1").ResultIU
       
    'Check to see if the shape hieght meets miminum for two connection points
    If H >= G Then
       
        'Sets number of needed connection points based on geometry of shape
        'Subtract G from the total height
        'G is 4.5 grid spaces (0.0625) for Broken Connector
        'G is 2.5 grid spaces (0.0625) for Whole Connector
        G = vsoShape.Cells("Scratch.A1").ResultIU
        N = ((H - G * 0.0625) / 0.125)
       
        'Get Existing Connection Points = C
        C = ActiveWindow.Selection(1).RowCount(Visio.visSectionConnectionPts)
           
        'Loop through all the rows
        For intRowIndex1 = 0 To C - 1
        Next intRowIndex1
           
            If C < N Then
                For I = C + 1 To N
           
                intRowIndex1 = ActiveWindow.Selection(1).AddRow(visSectionConnectionPts, visRowLast, visTagCnnctPt)
                WString = "Width*1"
               
                'Used for the Height Dimension of the connector to place the connection points
                G = vsoShape.Cells("Scratch.X1").ResultIU
                HString = "IF(Height*1> " & G & " + 0.125*" & intRowIndex1 - 1 & " ,Height*1-(0.125*" & I & "),0)"
                   
                Set vsoRow1 = ActiveWindow.Selection(1).Section(visSectionConnectionPts).Row(intRowIndex1)
                vsoRow1.Cell(visCnnctX).FormulaU = WString
                vsoRow1.Cell(visCnnctY).FormulaU = HString
                vsoRow1.Cell(visCnnctDirX).FormulaU = -1#
                vsoRow1.Cell(visCnnctDirY).FormulaU = 0#
                vsoRow1.Cell(visCnnctType).FormulaU = visCnnctTypeInward
           
                Next I
            End If
        End If
   
End Sub