VBA Script to draw a line of varying sizes

Started by markem, May 23, 2016, 03:05:31 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

markem

MANY years ago I tried to do this via VBA in Visio 2003 and I never could get it to work and after a few months I just gave up. I thought I'd try this again. Hopefully with a better outcome. :-)

What I want to do is to be able to draw a line and make it change widths as I draw it. I want it to do this based on two things : 1)The overall length of the line, and 2)A bit of randomness to grow and shrink the line as it is being drawn.  Basically, it emulates drawing a river.

Now, I did find a work-around that what I did was to use Fireworks to draw a randomly made line using a Grunge pattern. This actually worked quite well and I have used it ever since. But I'd like to do this all in Visio if possible.  By the way - I still use Visio 2003.  It works for me in all other respects so I just use it. :-)

When I talk about doing this I mean - I use the coloring pens.  This already allows me to draw a wobbly line that I use for a river. (See the first image.) The problem with this is that the line stays the same width throughout the drawing.  What the line is composed of though, are a lot of little line segments.  (See the second and third images.) What I want to do is to modify the line segments so they get bigger as you go along.

Although I am a programmer by profession - I never got in to VBA.  (More of an open source programmer.) So it is really very frustrating for me to not even have a clue as to how to start working on this let alone get it done.  I've followed Visio Guy's posts and looked at some scripts and I have no idea why but it just looks like gobbly-gook to me. :-)  Give me C++, OOP Javascript, OOP PHP - no problem.  But VBA?  My mind just seems to go into la-la land and I go "I don't get it."  :-D  And here I've taught thousands of people how to program everything from Basic up to C++.

So my questions are two fold: 1)Can someone help me out here?  or 2)Could someone point me to something that would be vaguely like what I need?  Maybe I can gimp along and figure it out but at this point I'm just drawing a blank.

Thanks in advance. I really appreciate your help.  This has been an on-going almost ten year project for me. :-/

JuneTheSecond

As I am very bad in English, I'm affread l cannot understand your beautiful English.
But I thought you could like a custom line pattern.
https://support.office.com/en-us/article/Add-a-new-fill-pattern-line-pattern-or-line-ends-pattern-bc636108-1fe1-4a24-8ec5-6b7de8b16dca
Best Regards,

Junichi Yoda
http://june.minibird.jp/

markem

Yes, thank you very much for posting that. :-)

Here is what I am looking at in more detail. The top line is a NURBS line which has a lot of points in it.  What I want to do is to get all of those points, then check them against each other as you go along the NURBS line so if any of the points are on the same slope they are dropped. (i.e.: If you have three points labeled A, B, & C and the slope for AB is the same as the slope for BC then you can drop C because it is on the same line and is thus not needed). Then create a set of lines that go from A->B->C->D->E... but make each line segment slightly different. What I am envisioning is that the line starts off with a width of 1 pixel. Then, as you go down the line this value slowly increases by one or two pixels - but it can also decrease.  So a randomization routine like this:

var A = rand(0,3) - 1;

The above would give you either -1, 0, 1, or 2.  So the line can grow or shrink by one pixel, remain the same width, or grow by two pixels. Also, if the random number that comes back would make the line's width go to zero - it stays at 1 pixel.  A program in pseudo code would be:

Start routine
   Get the list of NURBS points
   Delete the first four numbers because they just set up the NURBS function.
   Go through the list and remove the TYPE information because we just want the points.
   Go through the list of points we now have and check to see if three points are on the same slope.  If so, remove the middle point. Recheck until all points are unique.
   Set width to 1 pixel
   Delete NURBS line
   Set variable A to first point and variable B to second point
   Draw first line
   Begin loop to go down the list of points starting at third point
       Make A = B (ie: move second point to first location)
       Make B = Next point
       Get random offset for the width (ie: -1, 0, 1, or 2)
       Add offset to width.  If width is less than one reset it to one
       Draw new line segment
       Repeat until through all of the NURBS points we have
End routine

That's the entire routine.  :-)

I'm going to go search through the site and see if I can't find some VBA scripts.  Maybe that will give me enough information so I can write this. :-)  Anyway, thanks again! :-)

wapperdude

#3
Couple of points:

1)  V2003 severely limits what you can do.
2) I'm not aware  ability for a single line to have multiple line widths except with custom line patterns.  But, that's not the solution you're after.

Beginning with V2013, you could draw a nurb line programatically, https://msdn.microsoft.com/en-us/library/office/ff767094.aspx

I think the best solution might be vba routine that allows you to concatenate end to end individual line segments.  The code could randomize fcn for each line and modify the width.  So the code might use cursor down event to capture all of the line points and store these in an array.  Then step thru array, draw a line, set its width, then move to next point, new line & width, repeat for all  points.  The "shared" way points might be glued together.  That  way, each way point could be adjusted manually to tweak the composite line routing.

Just a thought.

Wapperdude
Visio 2019 Pro

markem

@WapperDude : Yeah, that is basically the pseudo code I posted except I'm thinking that you first draw the line via a INK option, convert to a NURBS line and then change that new NURBS line to the multiple line segments.

That is the example I showed.  My first problem was - I couldn't even get Visio to run a simple "Hello World" script.  Finally got that to work. Took me long enough.  That's my big problem - no experience using VBA at all.  And I've been programming since 1972.  My main programming has been via Unix and then Linux.  So mainly open source stuff.  When I switched to Windows it was mainly to do open source C/C++ on the Windows side and then Perl and then PHP.  So little to no actual Windows programming.  I do have Borland's old C++ compiler or maybe I could write my own 2D CAD program using CodeBlocks - but VBA is just kicking my butt.  It's like being back in first year college! Hah! :-)

I am looking at examples, like the ShowNames subroutine someone posted but it uses something from 2007 that 2003 doesn't have. I know there has to be a way to pick up on a selected shape. Even though Visio 2003 may not have everything the later versions have - it has to have a way to get what you selected and then to get the value of one of the cells in the stylesheet.  (The NURBS information is in one of the cells as a function call.) Then I just need to iterate through the list of points to get my array.

My problem is getting to that point. :-)

wapperdude

Use the macro recorder to get familiar.  Do something basic...like select a shape, change line width, change line color, move an end point, move the line.  Not all at once, make separate macros.

Download the free SDK for V2003.  Lot of examples.

Visio 2019 Pro

markem

Ok. So here is the ShowNames subroutine:

Public Sub ShowNames()

    'Declare object variables as Visio object types.
    Dim vsoPage As Visio.Page
    Dim vsoDocument As Visio.Document
    Dim vsoDocuments As Visio.Documents
    Dim vsoPages As Visio.Pages

    'Iterate through all open documents.
    Set vsoDocuments = Application.Documents
    For Each vsoDocument In vsoDocuments

        'Print the drawing name in the Visual Basic Editor
        'Immediate window.
        Debug.Print vsoDocument.FullName

        'Iterate through all pages in a drawing.
        Set vsoPages = vsoDocument.Pages
        For Each vsoPage In vsoPages
 
            'Print the page name in the Visual Basic Editor
            'Immediate window.
            Debug.Print Tab(5); vsoPage.Name
 
        Next

    Next

End Sub


This DOES work in Visio 2003.  Sorry, my mistake. The names appear in the IMMEDIATE window. (Again, newbie at trying to make this work - so sorry - thought it wasn't working before.)

Ok. So the first image shows a line I drew with the INK tool.  Then I selected it and converted it to a line geometry(2).  Then I selected it again (3). And finally I'm showing the StyleSheet part that has the NURBS info in it (4).

So I actually DO have a program that will show me the names of the open drawing window and page.  Now I need to get the name of the selected shape.

markem

#7
@WapperDude - Ok - I'll try that.

That's weird.  Visio 2003 won't let you use the INK tool when recording a macro.  :-?

It also won't let you convert Ink to line Geometry either under macro recording. :-(

wapperdude

Assuming you somehow selected a shape, either manually or programmatically, then to get it's name:

MsgBox ActiveWindow.Selection(1).Name

This will splash a message box with the Name.  You can use the debug print if you are fine with that.

Sometimes it's helpful to have the Visio drawing window and the VBA code window open side by side.  Then, if you want to follow what the code is doing, put your cursor in the code and then press <F8> to step thru the code line by line.  Easy access to the code window:  alt + <F11>

Wapperdude
Visio 2019 Pro

wapperdude

#9
Correct, ink is disabled when macro recorder is running.

Should be able to do what you want with code.  Your pseudo-code should work.

If you run macro recorder, then draw a simple line, you'll get feel for the coding.  Then, google visio vba draw line or drop line shape onto drawing page, or something like that.  Should give you sample code.

Edit:
Quick search you'll get this:  https://msdn.microsoft.com/en-us/library/ms195963(v=office.12).aspx
This is for V2007, but most will be valid for V2003.


Sub Macro2()
    Application.ActiveWindow.Page.DrawLine 2#, 5#, 5#, 7#
    MsgBox ActiveWindow.Selection(1).Name
   
    ActiveWindow.Page.DrawLine 1, 1, 6, 7
        MsgBox ActiveWindow.Selection(1).Name
End Sub


The shape remains selected after it is drawn.  The msgbox gives the name of the selected line.

Hash marks are from macro recorder.  2nd line shape was entered by hand, sans #.

HTH
Wapperdude
Visio 2019 Pro

markem

@WapperDude : Thanks!  I have two monitors and put the drawing area on the left, coding on the right.

Also - that's what I mean - this should be very simple for me but not being a VBA person really gives me a kick in the head as I don't have a feel for how to find what I need to do. :-(  So unlike me. But what can I say? I'm reading FileMaker Pro v10 manual and WordPress manual at the same time because I also wanted to learn how to program something in WordPress.  It helps I already know PHP, jQuery, Javascript, CSS, XML, XHTML,and...well...you know how web programming is probably. :-)  Already have something like 30 different languages running around in my head - need to integrate VBA into it all.  I expect computer tape to start spewing out of my ears any day now. :-D  Thanks again!

wapperdude

Ok.  You win!!!  😱  I now have a headache.   :)

Actually, I don't do much programming.  There isn't a lot of  in a  nice organized approach.  It's pretty much become comfortable with VBA object model, use macro recorder, look at examples, and search the web.

So, for me, it was dangle the feet in the water, and then slowly ease yourself all the way in.  I am by far, no expert, nor very proficient.  But patience and perseverance usually win out...plus lots of help from the forum friends.
Visio 2019 Pro

markem

@WapperDude - Yes.  I agree.  :-)

I found this:

Public Sub DebugPrintCellProperties()
' Abort if ShapeSheet not selected in the Visio UI
    If Not Visio.ActiveWindow.Type = Visio.VisWinTypes.visSheet Then
        Exit Sub
    End If
Dim cel As Visio.Cell
    Set cel = Visio.ActiveWindow.SelectedCell
'Print out some of the cell properties
    Debug.Print "Section", cel.Section
    Debug.Print "Row", cel.Row
    Debug.Print "Column", cel.Column
    Debug.Print "Name", cel.Name
    Debug.Print "FormulaU", cel.FormulaU
    Debug.Print "ResultIU", cel.ResultIU
    Debug.Print "ResultStr("""")", cel.ResultStr("")
    Debug.Print "Dependents", UBound(cel.Dependents)
' cel.Precedents may cause an error
On Error Resume Next
    Debug.Print "Precedents", UBound(cel.Precedents)
   
End Sub


Here: https://msdn.microsoft.com/en-us/library/office/gg144579%28v=office.14%29.aspx

This kind-of tells me how to get the NURBS information.  Trying to use your selection stuff to first get the converted line.  Then get the NURBS information.  That would be two down if I can get it to work. :-)

wapperdude

Here are some additional references that may be helpful:

VBA
https://msdn.microsoft.com/en-us/library/aa201749(office.10).aspx
https://msdn.microsoft.com/en-us/library/aa245244(v=office.10).aspx

shapesheet:       
https://msdn.microsoft.com/en-us/library/ms427031.aspx
https://msdn.microsoft.com/en-us/library/aa200961(office.10).aspx
https://msdn.microsoft.com/en-us/library/aa201763(v=office.10).aspx
https://msdn.microsoft.com/en-us/library/aa217840(v=office.10).aspx

VBA:  When referring to a cell in the shapesheet there are two syntaxes:
   .CellsU(...)
   .CellsSRC(..,..,..)

To enter info into a cell, there is .FormulaU() syntax, and related variants.
To fetch info from a cell, there is the .ResultStr() syntax and related variants.  Suggest looking these up and checking out examples.

This ought to get you moving forward.
Visio 2019 Pro