Arielus Posted July 27, 2021 Share Posted July 27, 2021 How can I create a parametric object with Vectorscript?. For example, I want to create a rectangle that has a certain figure inside but which can use that figure as a symbol and which can change the parameters in the object information palette. I want to create this figure as a symbol and have parametric properties to change each point independently. Thanks!! Quote Link to comment
michaelk Posted July 27, 2021 Share Posted July 27, 2021 Are you asking how to script it (https://developer.vectorworks.net/index.php/Main_Page) or how to turn the script into a parametric object? If that seems like overkill, have you checked out Marionette? Quote Link to comment
Arielus Posted July 27, 2021 Author Share Posted July 27, 2021 I would like to learn how to create a parametric object by script (I'm not sure if it can be done) because I want to learn how to create parametric objects first, whether using phyton or Vectorscript before learning Marionette Quote Link to comment
michaelk Posted July 27, 2021 Share Posted July 27, 2021 It can easily be done 🙂.* Are you familiar with VS or Python? *This is said by everybody at the start of a scripting project. Never actually true 🙂 Quote Link to comment
Arielus Posted July 27, 2021 Author Share Posted July 27, 2021 Being honest, I don't... that's why I want to learn with basic objects or forms so I can understand how it works and learn a lot more. I'm usually self-taught, but now I'm hard to be. Quote Link to comment
Peter Vandewalle Posted July 27, 2021 Share Posted July 27, 2021 You’ll need to start by creating a parametric object in the plug-in editor in the tools menu. You could create a rectangular object, that’s one of the options. In the same plug-in editor you can also add parameters and add the script. That can be Vectorscript or Python. you can also import an external file into that script. That external file can then hold the main part of the script. Quote Link to comment
Arielus Posted July 27, 2021 Author Share Posted July 27, 2021 Perfect, thank you so much, I'm gonna try that… Quote Link to comment
michaelk Posted July 27, 2021 Share Posted July 27, 2021 Post back if you get stuck. Happy to walk you through it. Quote Link to comment
Jesse Cogswell Posted July 29, 2021 Share Posted July 29, 2021 Vectorscript, which is itself based on an old language called Pascal, can be a bit obtuse (the biggest hurdle I had coming from Java and Python was figuring out how to properly use handles), but there are a lot of code examples that can be found on the online wiki as well as the offline Function Reference. On a Windows machine, that function reference is stored in C:\Program Files\Vectorworks ####\VW Help\Script Reference\ScriptFunctionReference.html. I assume it's stored in a similar manner within the application folder on a Mac. While I'm working on scripts, I always have it open somewhere, usually on a second monitor. It's faster to navigate than the online wiki, and you don't need a connection for it to work. For Python, there are a ton of online resources to teach yourself the language, but the implementation in Vectorworks is a bit tricky. You will still need to use the commands found in the Function Reference to interact with VW, but you will gain far greater control in terms of how you handle data. I learned Python several years before it was available in Vectorworks, and by the time they implemented it, I was more comfortable with Vectorscript, so that's primarily what I work in. If you do want to go through the process of learning Vectorscript, an excellent starting point would be the Vectorscript Language Guide, which used to be part of the main VW help but has since moved off to this separate document. It's what I used to teach myself back in 2010, and it's pretty easy to follow as far as these things go. Quote Link to comment
Arielus Posted July 29, 2021 Author Share Posted July 29, 2021 Will there be some video tutorial to perform processes and create objects or elements in Vectorscript? Quote Link to comment
Pat Stanford Posted July 29, 2021 Share Posted July 29, 2021 But at least Vectorscript is not white space delimited where a single extra space can completely change how a program acts. 😉 Give me the extra typing of Begin/End any day over having to get spacing correct. I though I had seen the last of that when I finished my Fortran class in 1983. 2 Quote Link to comment
Jesse Cogswell Posted July 29, 2021 Share Posted July 29, 2021 @Pat Stanford No kidding, Python can be a huge pain to debug because of the incredible freedom it gives you and it being a run-time language. For all its rigid quirks and archaic rules, Vectorscript is at least pretty forgiving and easy to debug (as long as you don't cause a memory leak leaving out a parenthesis in a ForEachObject call...), especially after 2016 when they finally added in line numbers to the IDE. @Arielus Putting "Vectorscript" into the search field in YouTube does yield some results, but there doesn't appear to be a full tutorial. Coding in general is something that I think video tutorials are not super great at, as scripting is a written medium as opposed to a visual one. If you are looking for a more visual focused method of object creation, I would suggest trying out Marionette, of which there are several training videos from Vectorworks (like this one here). I find Marionette clunky and slow since I can type much faster than clicking and dragging variables around, and Marionette objects run slower than scripted plug-in objects (though this did start getting much better starting in VW2020). I think jumping in to Vectorscript without any coding experience might be a bit daunting, especially because of its relative lack of "beginner friendly" documentation. I would suggest looking into an online course for a more common language to learn the basics of coding such as C, C#, or Java. Python is a tricky first language because of the way it "bends" a lot of the rules of programming. It was designed as a language that could be picked up in a day with any experience in coding, but it could teach you some bad habits that would hamper you in working with other languages. Quote Link to comment
Pat Stanford Posted July 29, 2021 Share Posted July 29, 2021 For a relatively high level explanation of Vectorscript, see this thread in the Resource Share - Vectorscript forum. Resource Share is mostly information carried forward from the older version of the forum, but there are a lot of good scripts there. I try to comment most of the scripts I post to make them understandable and as a learning tool. @Jesse Cogswell@michaelk and many others are all too willing to help with the learning process. My personal opinion is that Marionette is the best tool to make a parameterized object in VW if you don't have scripting experience. and Vector(Python)script is best if you want to do data manipulation on existing objects. Marionette takes away all of the complexity of getting and using data entered in the OIP that ends up being a lot of the script in most Vectorscript Parameterized objects. @Arielusfor yoru object above if you are always making a rectangle, you really only need three points. Bottom Left, Top Right, and the center point. I would probably start with a really simple version that is a fixed size rectangle and only work on the code to make the internal polygon. Once I got that working I would then go back and add the code to allow the change in the rectangle size. Ask again when you need more help. Quote Link to comment
Arielus Posted July 29, 2021 Author Share Posted July 29, 2021 Thank you very much for your support @Pat Stanford@Jesse Cogswell@michaelk, I think it would be very useful to upload videos or documents where they indicate step by step how to create elements in Vectorscript, Phyton and Marionette, to be able to observe the procedure and the usefulness of it... that would be an excellent help. Quote Link to comment
MarcelP102 Posted July 29, 2021 Share Posted July 29, 2021 (edited) Perhaps you can look around some more. There is a lot of information available already. It's best for your object to make it with Marionette you can start to look at the Vectorworks YouTube page. Especially the playlist. Marionette Mondays playlist: Marionette tutorials playlist: Then there is the Marionette gallery: https://forum.vectorworks.net/index.php?/files/ And not to forget we have the Vectorworks University with loads of video's: https://university.vectorworks.net/course/index.php?mycourses=0&tagfilter[category]=35&tagfilter[type]=0&tagfilter[difficulty]=0&categorysort=default&mycourses=0&search=Marionette&langfilter[]=0#coursestab I advise you to check these places first next time you looking for information. Edited July 29, 2021 by MarcelP102 Quote Link to comment
Popular Post Jesse Cogswell Posted July 30, 2021 Popular Post Share Posted July 30, 2021 It's a slow day for me today, so here goes a quick crash course in Vectorscript. I'm going to try to keep things in a logical order, but between how Vectorworks handles plug-ins, standard coding practices, and Vectorscript structure and syntax, there's an awful lot to cover. I have built what I think you are looking for, and will attach the code and also walk you through it so you understand what it is doing. I am going to write all of this down rather than doing a video. Personally, I find text instruction to be far more useful than video instruction, as it lets you move at your own pace and hopefully won't make you feel rushed. HOW VECTORWORKS DEALS WITH PLUG-INS: Any plug-ins that you install or build yourself are going to be stored in your Vectorworks User Folder in the Plug-ins subfolder. The quickest way to track this down is open up your Vectorworks Preferences. In the User Folders tab, click on the button labeled Explore (Windows) or Open in Finder (Mac). This will open up an Explorer/Finder window with your user folder. From there, open up the Plug-ins folder. When you create a new script through the Plug-in Manager, it will be stored here. Likewise, if you want to install a plug-in, you can drop the .vso (plug-in object), .vsm (menu command), or .vst (tool) into this folder. This folder is scanned when the program first boots up, so after installing a command, make sure you reboot Vectorworks if the program is already running. No need to restart if you create a new script, however. TO PLACE PLUG-IN INTO WORKSPACE: Installing the plug-in is only half the battle. You will need to make sure that it is part of your workspace before you can start using it, even if it's a plug-in you've created yourself. To do this, follow the instructions below: Open up the Workspace Editor by clicking Tools - Workspaces - Edit Current Workspace. This will open a dialog with all installed menu commands/tools shown in the box on the left, and where they appear in your workspace in the box on the right. Menu commands will be found in the tab marked Menus, while plug-in objects and tools will be found in the tab marked Tools. In the box on the left, find the category of the tool (we'll cover this in just a little bit) and expand it. In the box on the right, find where you want the script to live in your workspace and expand it. Click and drag the plug-in from the left box to the right box. Be mindful of "nesting", it can be really easy to accidentally nest a tool inside another tool, requiring you to right-click the parent tool in the tool set to get to the nested one. Click OK. This will reset your workspace and add the new tools. PLUG-IN TYPES: Before we get to plug-in creation, we should chat about what the different types are and where to use them. COMMAND: This is a menu command, designed to be placed in the main menu bar at the top of the screen. These generally execute a series of commands in a similar fashion as a macro. These commands might manipulate selected objects (such as Convert to Group, Add Surface, etc), create geometry (Create Roof), or any number of other things. TOOL: The Tool type plug-ins will appear in a tool set in your workspace and are designed to manipulate existing objects, usually requiring that you click on the object after launching the tool. Examples of this are Select Similar (magic wand tool), Trim Tool, Offset Tool, etc. I personally don't write tools very often, but it's a pretty common practice to use a Tool type plug-in to place a Plug-in Object type plug-in. This can be seen the Door and Window tool. I'm not entirely sure what the advantage of doing so is, but maybe someone else can explain it. PLUG-IN OBJECT: Usually abbreviated to PIO, this is the type that creates the parametric objects that you are looking for. This type encompasses: Point Objects: Objects with a single insertion point. They will not have resize handles, any changes will need to be made from the Object Info Palette. These would be things like Data Tags, Windows, Doors, etc. Linear Objects: Objects needing two clicks to insert. These will have two resize handles, one at each side of the "line" of the PIO. This will automatically generate "LineLength" parameter (more on this in a bit). These include things like lines, Walls, and Dimensions. Rectangle Objects: This is the type that we will be using for your plug-in. Keep in mind that these do not function in the same manner as the Rectangle Tool. Rather than clicking a top-left corner and a bottom-right corner, you will instead click once to determine a starting point, a second time to determine width, and a third time to determine height. No idea why it works that way other than that it is likely left over from the original days of Vectorworks/MiniCAD. In any case, once an object is created, you will have the full set of resize handles at your fingertips. 2D Path Objects and 3D Path Objects: These work in the same fashion as the Polygon and Polyline tool, multiple clicks to form a path. I've never built a path-type plug-in, so if you have any questions, you'll have to ask someone else. INCLUDE FILE: This is a text-based resource file that can be externally referenced. I use these commonly to store dialog box settings and data that I don't want hard-coded into the plug-in. CREATING A NEW PLUG-IN: Okay, with all that out of the way, let's get started on actually building a plug-in. Open up the Plug-in Manager by going to Tools - Plug-ins - Plug-in Manager. You'll be opening this a lot, so I recommend memorizing the shortcut keys (Ctrl++Z on Windows). This dialog box has three tabs: Custom Plug-ins: Any plug-ins you create will appear here. Also, any installed plug-ins that are not encrypted will appear here as well. These plug-ins are able to have their source code edited. Third-party Plug-ins: These are plug-ins found in your Resource Folder that are encrypted. You will be able to change definition data, but won't have access to the source code itself. This tab is also where you will find the "easy" Install button. More on that later. Built-in Plug-ins: These are the plug-ins that come with your install of Vectorworks. They will be encrypted and have their source code locked. For what we will be doing, make sure you are in the Custom Plug-ins tab. From there, click on the New button. This will launch a dialog asking us what type our plug-in wants to be. For the purposes of building your plug-in, select Rectangle Object and give it a name. Click OK. This will create an empty plug-in. Before we can get to writing the script, select the plug-in and click on the Edit Definition button. This will allow us to set up the parameters that will appear in the Object Info Palette. In the General tab, select a category for the plug-in. This is what sets the category in the Workspace Editor. Typically, I will use my initials (JNC) for any custom plug-ins that I write, or will put it in a category of "Research and Development" if it's a plug-in I'm testing things with. Open the Parameters tab. This is where we will build the parameters found in the Object Info Palette. You will notice that two of those already exist, LineLength and BoxWidth. as those are automatically generated for Rectangle Objects. This window has five different columns: #: This is order in which the parameter will appear in the OIP. This number is also the number used to correlate with the parametric record of the plug-in (more on this later). Name: This is the name that we will use in the code to pull the parameter data from. The naming of this should follow general variable naming conventions, namely that it wants to start with a letter and have no spaces in it. If you want a parameter to not appear in the OIP, you can add a double underscore (__) to the Name and it will be hidden. This is common when using parameters to store background data that the plug-in needs, but the user doesn't need to know about. Alternate Name: This is what the parameter will appear as in the Object Info Palette. This allows a plug-in to be localized without having to change the source code directly. Type: This will show what the parameter's type is. This can be the direct primitive types (explained later), which would be entered through a straight field in the OIP, a boolean type (checkbox in the OIP), or even pull-down menus and radio buttons in the OIP. Default: This is the what the parameter will populate by default when first being dropped into a drawing. For anything with numbers, this field must be populated with something. Select the first parameter, LineLength and click on the Edit button. We'll want to enter something friendlier in the Alternate Name field, I recommend "Width" if building this tool in English. I understand that this seems wrong with the parameter name being called "LineLength", but it's a quirk of Rectangle Tools, the naming is backward. Click OK. Select the second parameter, BoxWidth and click Edit. Change the Alternate Name field to "Height" and click OK. Now, we need to add in the ability set the indent of your shaded polygon. The best way to achieve this is with a Control Point. Control Points act as added reshape handles as well as fields in the OIP. With that in mind, click on the New button. Control Points will automatically fill in the Name field, so don't worry about filling in that information. Select Control Point from the Type drop-down menu. Put something friendly in the Alternate Name field, something along the lines of "Indent." Put something in the default fields, I used 1 for each. You just want to make sure that it's not 0, as the reshape handle will end up on top of one of the rectangle's reshape handles in this case. Click OK. When you're done, you should have something that looks like this: For now, we can ignore the other tabs. If I remember, I'll add in a bit at the end explaining what each of them are used for. Click OK to close out the dialog window. NOW WE NEED TO TALK ABOUT CODING: Since you are new to coding, there are some concepts that you need to understand before you get started. Generally, Vectorscript does not care about white-space. You are free to indent where ever you want and are allowed to put as many spaces around things as you want. All lines need to be terminated with a semi-colon (for the most part...but we won't get into that here). Compartmentalized things like loops and Procedure/Function definitions are set between BEGIN and END statements. Any line encompassed by curly brackets ({}) is considered a comment and is not compiled. This is handy for adding notes, or temporarily removing lines of code for debugging purposes. The biggest thing to get your head around is the concept of variables. Variables are words that represent a piece of data within the code. These can generally be named however you like as long as they don't start with a number (can't have a variable named "1str", for example), aren't one of the "reserved words" (like "PROCEDURE", "CONST", "VAR", "BEGIN", "END"), don't conflict with an existing Function or Procedure (can't name a variable "Rect" because that would step on the Rect() procedure, but "Rect1" would be okay), and don't contain spaces. There are no hard and fast rules to this, it's whatever you need to make the code legible for you or anyone else needing to read it. My best advice is to just be consistent across the code as best as possible. Some conventions to consider adopting: Camel-case: This is a pretty common way of handling naming in code. For variables, the convention is to start with a lowercase letter, and only capitalize the first letter of each new word (since you can't have spaces in a variable name). An example would be something like "drwOrigin" or "thisIsMyVariableName". Procedures and Functions would be named similarly, only with a capitalized first letter, like "ThisIsMyProcedure". Vectorscript DOES NOT care about capitalization outside of strings, so it's mostly about legibility for the user, it won't care if you type "thisismyvariablename" or "thisIsMyVariableName", but someone trying to untangle your code will. Hungarian Notation: This is a pretty common way of naming variables in which the first letter defines what type the variable is. A string might be named "sMyString" while a number might be named "nMyNumber". For the purposes of demonstration, my example code will feature Hungarian Notation, but I generally don't use it, but only because I never got in the habit. It's a really handy way of keeping track of your variable types, so I would recommend implementing it. So, variables can be of any of a number of Primitive Types. These are the fundamental building blocks of the script. INTEGER: These are simple, non-decimal numbers in a range of -32767 to 32767. These are great for counting things and any operation that wants a whole number. LONGINT: These are whole numbers that exceed the range of an INTEGER. The range is great, between -2147183647 and 2147183647. These are commonly used in Vectorscript to store 16-bit numbers (for colors) and unique identifiers. REAL: These are your decimal numbers (known in other languages as floating-point values), and primarily are used for things like dimensions. STRING: A string is a collection of characters forming things like words. These are defined in code using single quotes, as in 'This is a String.' Back in the day, these used to be restricted to 255 characters, I'm not sure if that's been expanded since. CHAR: A single ASCII character. BOOLEAN: A data value that can be set to be either TRUE or FALSE. HANDLE: This is the hardest (at least it was for me) thing to wrap your head around. A HANDLE is a reference to an object that is needed for most functions in Vectorscript. In other languages, these would be referred to as "pointers." Since Vectorscript is not object-oriented, HANDLEs are used to specify what objects to run code on. The Document List Handling section of the Function Reference is going to be the best place to learn the different ways of pulling HANDLEs. VECTOR: These are complex little structures that are used for complex geometric computations. My calculus and trigonometry aren't the best, so I usually have to spend a lot of trial and error time to get these working properly. Essentially, each VECTOR is a Structure containing three REAL values, accessed by calling <variableName>.x, <variableName>.y, and <variableName>.z. I'll try to clarify that all in a bit. POINT: This is a 2D point, consisting of an X value and a Y value, both of which are REAL values. These discreet values are accessed by typing ".x" or ".y" after the variable name. For example, let's say we have a Point named "myPoint." The call to get to the X value would be myPoint.x and the Y value would be MyPoint.y. POINT3D: Same as the POINT type above, except it has an additional Z value. RGBCOLOR: A data structure containing three 16-bit LONGINT values, one for red, one for green, and one for blue. These are accessed in a similar manner as the POINTs above, with <variableName>.red, <variableName>.green, and <variableName>.blue. Variables in Vectorscript must be declared before they may be used, and them must be declared in the VAR block of code (explained below). Syntax for declaring is listing the name, the type, and separating with a colon. So, a STRING named "myString" will be declared with the script myString : STRING. Multiple variables of the same type can be declared at once, using a comma as a separator. As in, myString, alsoMyString : STRING. Once a variable is declared, it must be defined. This can happen anywhere in the code, but is recommended to be done before the variable is needed. If a variable is not defined, it will be set to something of a default state (strings will be set to '', numbers set to 0, handles set to NIL). To define a variable, the syntax is the variable name followed by a colon, then an equal sign, then a value. For example, a string would be defined with myString := 'blah blah blah'. A number could be defined as myInteger := 5. To pull the parameters that we set up earlier into the script as a variable, the syntax is a capital P followed by the parameter name (as found in the Name column on the Parameters tab. This means that if we wanted to pull the LineLength into a REAL variable named rWidth, the code would look like rWidth := PLineLength; Contant values are similar to variables, except that they are defined at the very top of the program and cannot be changed after being defined. They also do not need to have a type specified, it's handled in the definition. Syntax is the name followed by an equal sign, followed by a value. A typical definition looks like this kMyConstant = 0; Typical naming conventions for constants are to capitalize the whole name (as in MYCONSTANT), or to have a lower-case k in front, as in the example above. These are used for values that don't want to ever change in the code, such as preference selectors, parameter indexes, computational constants, etc. Next, we'll want to talk about Functions and Procedures. These are subroutines that you call to execute lines of code. Basically, you pass in variables (referred to as Arguments) into the call, and the code executes. Think of them as modules that are built to do a single task. They both fundamentally operate the same way, with the only major difference that a Function is designed to return a value. Consider the code below, the Procedure takes in two values, adds them together, then prints the text of the sum. The Function takes the same two values, adds them together, and returns the sum. PROCEDURE PrintSum(val1, val2 : REAL); BEGIN Message(val1 + val2); END; FUNCTION SumValues(val1, val2 : REAL) : REAL; BEGIN SumValues:= val1 + val2; END; The syntax for defining a Procedure is PROCEDURE ProcedureName (<insert arguments here>); The syntax for defining a Function is FUNCTION Function Name (<insert arguments here>) : <return type>; Arguments need to have their types declared, with different types being separated by a semi-colon. For example: PROCEDURE (myString1, myString2 : STRING; myInt1, myInt2 : INTEGER); The syntax for the return value of a Function is to use the Function name and to define a value for it, as shown above. VECTORSCRIPT CODING STRUCTURE: Now that we're starting to look at code, let's look at how a standard Vectorscript program is structured. Vectorscript is very rigid in how things have to be structured, so every script will be structured the same way. We think of the code broken down into different "blocks". While not every block needs to be present in the code, if you need constants then you must have a CONST block, if you need variables then you must have a VAR block. The only blocks required for the code to run are the Plug-in Definition, the Main Driver Block, and the Run Statement. Basic structure is as follows, example code in bold: __________ | Plug-in Definition: | PROCEDURE MyPlugin; |__________ | Constant Block: | CONST | kMyConstant = 'blah'; |__________ | Type Block: I'm not going to get into this one here, it's a very handy thing but outside the scope of this tutorial. More info can be found in the Language Guide | https://developer.vectorworks.net/images/7/72/VectorScriptGuide.pdf |__________ | Variable Block: | VAR | myString1, myString2 : STRING; | myNum1, myNum2 : REAL; | __________ | Embedded Procedures and Functions Block: | PROCEDURE PrintSum (val1, val2 : REAL); | BEGIN | Message(val1 + val2); | END; |__________ | Main Driver Block: | BEGIN | myNum1 := 5.5; | myNum2 := 3.1; | PrintSum(myNum1, myNum2); | END; |__________ | Run Statement: | Run(MyPlugin); |__________ All Procedures and Functions follow this same structure. It is even possible to embed Procedures and Functions inside other Procedures and Functions, though it's really bad practice outside of some necessary instances involving dialog box creation. Any variables declared in the main Variable Block at the top of the script are what we think of as global variables. These variables can be manipulated by any embedded subroutine as well as the main driver block. Variables declared within a Procedure or Function definition are only accessible within that definition, and are known as local variables. Generally, good coding practice is to avoid manipulating global variables outside of the main driver block, instead passing variables in to subroutines as arguments and returning the results. As an example from above, the PrintSum definition could instead look like this: PROCEDURE PrintSum; BEGIN Message(myNum1 + myNum2); END; The code won't stop you from doing this, but it makes the code much less modular and is considered bad practice. The final note about structure is that Vectorscript needs to be compiled before it can run. This means that the code is transferred into assembly language so that the computer can run it. To compile your script, click on the Gear icon in the Script Editor. This will highlight any errors and give you a line number to look at in order to fix the errors. What's important to note is that the code is compiled from top to bottom. This means that if you have an embedded Procedure calling another embedded Procedure, that called Procedure must appear above the call, otherwise the compiler won't know how to interpret the call. That being said, the code itself is executed as it is called, so it would start executing the Main Driver Block first, only executing embedded subroutines if and when they are called. NOW FINALLY, CODING YOUR EXAMPLE: You want to have something of an idea of the nuts and bolts of what you need the script to do. In your example, it needs to produce a rectangle as defined by the Rectangle Object plug-in type, then it needs to create a polygon using three of the points of the rectangle and a fourth indent point. Something to keep in mind with the Rectangle Object plug-in type, is that the insertion point of the plug-in (considered its origin), is on the left-most side at the center of the object, not the upper left most point. So any computations based on the Height parameter need to keep that in mind. Usually when I think about polygons, I label each needed point in the order that the polygon would be created. With that in mind, here's your sample: So the code essentially needs to compute out points A-D, then use those to build a rectangle and polygon. First thing's first, we'll want to open the Script Editor. Do this by opening up the Plug-in Manager, selecting your new plug-in, and clicking the Edit Script button. This will open what should be a blank page. Make sure that the language is set to Vectorscript, and you should be good to go. The button in the upper left is something of a shortcut to Procedures/Functions from the Vectorscript library, a criteria builder, a parameter selector, and a text file browser. I don't use it very often, but I can see some value in it. The button to the right of that that has a gear on it is the Compile button. Press this to make sure that there are no errors in your code. All code used below that have listings in the Function Reference have links to their respective pages in that reference. I HIGHLY recommend clicking on those and getting comfortable with how the Function Reference is formatted. So, in the Main Variable Block, I'm going to declare four POINT variables (pA, pB, pC, and pD), two REAL variables (rWidth, and rHeight), and a HANDLE variable (hObj). Then, in the Main Driver Block, I'm going to: Pull in parameters and set them into variables using rWidth := PLineLength; and rHeight := PBoxWidth; Compute the four points pA: X is easy as it is just the origin (0), so pA.x := 0; Y will be equal to half of the height, so pA.y := rHeight / 2; pB: X will be equal to the full width of object, so pB.x := rWidth; Y will be the same as pA, so rather than computing it out, I can call pB.y := pA.y; pC: This one is a little trickier, it will be defined by the Control Point parameter we put in. The call will be pC.x := PControlPoint01X; and pC.y := PControlPoint01Y; pD: X will be the same as pA, so pD.x := pA.x; Y will be 0 minus half of the height, so pD.y := 0 - (rHeight / 2); You could also do pD.y := pA.y - rHeight; Now that the four points have been computed, I'm going to call the CreateArielusObject function, using the returned HANDLE to define variable hObj. The CreateArielusObject function will do the following: Pull in four points as arguments, accessed using the local variables p1, p2, p3, p4. With the points we passed in, p1 has the same data as global variable pA, p2 has the same data as pB, etc. In the Local Variable Block, we're going to declare an RGBCOLOR variable, clrPen, to set the color of the polygon component, as well as a temporary HANDLE, h. Define a group using the BeginGroupN procedure. This procedure is a little different in that it is set to return a value through its arguments, done by placing VAR in front of the argument in the definition (you'll see that if you click on the link to the Function Reference). So once the group is complete, variable h will now be a HANDLE pointing to the group. The full call looks like BeginGroupN(h); As a demonstration of where the insertion point of the object is, I'm going to place a Locus Point at 0,0 using Locus. Full call is Locus(0, 0); Next up is creating the rectangle using Rect. This procedure takes in the upper-left and bottom-right points as arguments to build a rectangle, but as four separate REAL values. While we don't have a variable for the point of the bottom right corner, we can get it from points p2 and p4 (same as pA and pD). Full call is Rect(p1.x, p1.y, p2.x, p4.y); This rectangle will have the same visual attributes as the plug-in object. So, if we want to pull the pen color to use as a fill for the polygon we're going to make next, we'll want to use the GetPenFore procedure to pull the data. This procedure takes in a handle, and returns the red, green, and blue color values as 16-bit LONGINT values. In order to get a handle to the rectangle, we'll use the LNewObj function, which returns a HANDLE to the most recent new object. We can combine the two calls into a single line of code with GetPenFore(LNewObj, clrPen.red, clrPen.green, clrPen.blue); Next, we'll want to create our polygon. When thinking about 2D objects made up of different components, it's best to build from bottom to top. Before we build our polygon, we'll want to use the ClosePoly procedure to ensure that our polygon will be closed. By default, the script will create open polygons, so the last line will be missing. Next, we'll use the Poly procedure to create our polygon. This takes in an unlimited number of pairs of REAL values (one for X, one for Y) to create a polygon object. With that in mind, our call is going to be Poly(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y); Then we'll want to apply the pen color from the rectangle as the fill color of the polygon using the SetFillBack procedure. This takes in a HANDLE and three LONGINT values to set the handled object's fill color. We'll use LNewObj again to get the HANDLE to the polygon. SetFillBack(LNewObj, clrPen.red, clrPen.green, clrPen.blue); We'll use EndGroup to close out the group. After this point, local variable h will now be a HANDLE to both the rectangle and polygon objects grouped together. The very last thing we'll need to do is to set the returned value for CreateArielusObject to be the same as h, using CreateArielusObject := h; And that's the code. Typically for Functions, I will almost always have a temporary local variable with a short name (like h) to do calculations with, making the last line of code for the Function used to define the Function return as that temp variable. The full code for the plug-in should look something like this: PROCEDURE ArielusTest; {* Parametric demonstration for Arielus Developed by: Jesse Cogswell Date: 7/29/2021 VW Version: 2019 Revisions: *} CONST {Constant Block with examples, not used in the code} kExampleNum = 1; kExampleString = 'This is an example'; VAR {Main Variable Block, these are Global Variables} pA,pB,pC,pD : POINT; rWidth,rHeight : REAL; hObj : HANDLE; FUNCTION CreateArielusObject(p1, p2, p3, p4 : POINT) : HANDLE; {Embedded subroutine} {Creates parametric object using given points and returns handle to object} VAR {Local Variable Block} clrPen : RGBCOLOR; h : HANDLE; BEGIN BeginGroupN(h); {Everything between BeginGroupN and EndGroup will be placed in a group together, with handle argument being the handle to the group} {Create Locus Point at Origin to demonstrate insertion point} Locus(0, 0); {Create rectangle} Rect(p1.x, p1.y, p2.x, p4.y); {Rectangle defined by upper left corner and lower right corner} GetPenFore(LNewObj, clrPen.red, clrPen.green, clrPen.blue); {Pull pen color of rectangle} {Create polygon} ClosePoly; {This command instructs the next polygon that it will be closed} Poly(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y); {Polygon defined by four points, A-D} SetFillBack(LNewObj, clrPen.red, clrPen.green, clrPen.blue); {Pen color applied as polygon fill color} EndGroup; {Set return value as handle to created group} CreateArielusObject := h; END; BEGIN {Main Driver Block} {Pull in parameters into variables} rWidth := PLineLength; rHeight := PBoxWidth; {Compute points A-D} pA.x := 0; pA.y := rHeight / 2; pB.x := rWidth; pB.y := pA.y; pC.x := PControlPoint01X; pC.y := PControlPoint01Y; pD.x := pA.x; pD.y := 0 - (rHeight / 2); {Call Function to create object} hObj := CreateArielusObject(pA, pB, pC, pD); END; Run(ArielusTest); {Run Statement} If you want to look at the code in the actual IDE (very highly recommended, as the text will color-code itself which makes things easier to read), download the attached file (Arielus Test.vso) and place it in the Plug-ins subfolder of your User Folder in the process outlined above. Restart Vectorworks, then the plug-in should appear in the Custom Plug-ins tab of the Plug-in Editor. Then you should be able to select it and press the Edit Script button to open it up in the Script Editor. That about does it from me. That's a lot of information and I hope you find it useful. Keep in mind that this barely scratches the surface of what Vectorscript can do. It really requires a lot of trial and error and frequent reading of the Function Reference. I also HIGHLY recommend going through the Vectorscript Language Guide, found here: https://developer.vectorworks.net/images/7/72/VectorScriptGuide.pdf. It's the actual instruction manual on all of this and it will have a lot of examples of code. Please let me know if you have any questions. This is a lot but I invariably missed some things. Arielus Test.vso 14 Quote Link to comment
willofmaine Posted October 23, 2021 Share Posted October 23, 2021 @Jesse Cogswell Excellent crash course in Vectorscript; thank you for putting this together. I stumbled across it out of an extreme frustration with Marionette's instability and in search of an alternative to Marionette. I was able to take your script, add it as a plug-in, and successfully make some changes (such as adding another point and adjusting the colors). Any particular reason you alternately use numbers and letters to identify what appear to be the same points? When I changed all of the numbers for points in your script to their corresponding letters, the script continued to work fine. Looking at some scripts gave me some ideas that I think I've successfully implemented into Marionette so, between that and yet another Marionette work around or two, I'm continuing with Marionette... at least for now. I can see that it would take a huge time investment to become proficient with Vectorscript or Python. In the meantime, again, thank you for your crash course! Quote Link to comment
Jesse Cogswell Posted October 23, 2021 Share Posted October 23, 2021 @willofmaine The reason I alternate between letters and numbers for points in this example is more or less down to how I name and handle variable names between formal declarations (declared in the VAR block of code) versus variables named in the PROCEDURE/FUNCTION definition. Almost always, I will name points with capital letters, both because of ease of typing (handling points requires a lot of lines of code since each X, Y, and Z setting requires its own line), and because of how I learned geometry in high school. That all being said, because of the way Vectorscript handles PROCEDURE/FUNCTION definition, you need to declare what variables and in what order the constructor will be looking for as "arguments." While you technically can pass in the same global variables into the constructor, it's best practice to keep them as local variables within the definition (allowing for better modularity of code, even if Vectorscript really has no way of sharing code from script to script). I'm often lazy when dealing with constructor arguments, so I'll often just name them as the variable type followed by a number (s1,s2,s3 for STRINGs; h1,h2,h3 for HANDLEs; i1,i2,i3 for INTEGERs; p1,p2,p3 for POINTs) rather than giving each a more unique name that I have to remember and not conflict with an existing variable name. At the end of the day, Vectorscript or Python don't really care what you name your variables as long as they don't start with a numeral, and that they aren't the same name as an existing function or special word (can't name a variable var because of the VAR special word, or count because of the existing Count() function). Special words should be obvious as most IDEs will color them separately to highlight them, and naming a variable a function will throw an error in the compiler (or during runtime with Python). I'm glad that you got some use out of the crash course. Learning a programming language is definitely something I'd recommend, and the hardest language to learn is the first. Once you learn one language, a lot of the ideas will translate to another, then it's a matter of learning syntax and flow. Python is at once a wonderful language to start with (it's used pretty much everywhere nowadays, there are a TON of resources to learn it from, and, as far as programming languages go, it's really simple to learn), but also does so many things for you that it can be hard to transition to another language. Learning Vectorscript as your first language will also be challenging just because your resources are restricted to this forum and the developer wiki, as Pascal hasn't been a super relevant language in the last 25 years, so there are far fewer online resources. But at the same time, the Python implementation in VW is built on the Vectorscript function library, so knowing Vectorscript makes scripting in Python for VW so much easier. I'm pretty bummed with how Marionette has gone. When they first debuted it in 2016, I was really excited about the possibilities. It was even the very first thing I played with in VW2016, but it's very clunky as far as visual scripting goes, and I've always found it sluggish to both program in and the performance of Marionette objects. And overall, its implementation hasn't changed much since its inclusion, even in VW2022 Marionette objects are sluggish (though they take up far less in terms of file size, so that's nice at least). My twin brother works in the digital animation industry and uses node-based visual scripting in Blender and XSI SoftImage and was horrified when I showed him how it works in Vectorworks. Best of luck continuing your Marionette and scripting journey. Please feel free to let me know if you have any further questions. 1 Quote Link to comment
willofmaine Posted October 24, 2021 Share Posted October 24, 2021 @Jesse Cogswell Ah... so there is a method to your madness. I'm not surprised, really... And again, thank you for taking the time to explain, and for your thoughts on scripting and Marionette. Like you, I was very excited when Marionette was introduced (I hadn't ever seen graphic scripting before), and I whole-heartedly embraced it. But at least two, maybe three times in the past I've abandoned Marionette, each time swearing to never return. But I just couldn't let it go; I've created a sizable collection of extremely useful (when they work) Marionette objects, all well worth the time invested in creating them (excluding the time lost fighting with their many issues). Even though I've got my latest Marionette working (at least for the moment...), I think I'll actually change my mind and follow your recommendation of learning a programming language; at least now I can do it at my own pace, maybe so that the next time Marionette's disagreeable I'll have a viable alternative in the works... So the question is, which language? @Pat Stanford had suggested Python as a first language, though he also complained about its being "white space delimited." I can find plenty on the Web for Python, but nothing specifically for Python within Vectorworks... and the two implementations look different to me. So, at least for starters, I ended up pursuing Vectorscript, thanks to your crash course. And looking just now, I can't seem to find a simple Python-based plug-in object that I could try and reverse-engineer from; everything seems to be Vectorscript. Do you by any chance have, or know of, a crash course in Python?? Thanks!! Quote Link to comment
Jesse Cogswell Posted October 24, 2021 Share Posted October 24, 2021 Python is probably the easier language to learn, and it comes with the added benefit of being applicable to Marionette since the nodes use Python to determine their operation. There are also a TON of classes online that teach Python. Don't be worried too much about it being white space delimited, it just means that you have to be very strict about how you use tabs and spaces or the code won't work properly. Python does get a little tricky in this regard, as its not a compiled language like Vectorscript, so there's no error checking until it's running, and it can be tricky tracking down what is causing the code to break. Unfortunately, I'm not too familiar with Python's operation in Vectorworks. I learned Python on my own back in 2010, but haven't really touched it since aside from editing a couple of Marionette nodes. By the time it was added to Vectorworks (2015 maybe?), I was very comfortable with Vectorscript and didn't have much need to switch. I am working on a project to add copy protection into some of my plug-ins that will require Python in order to ping an online database (there doesn't seem to be any way to do this with Vectorscript natively), and another project to ease the update process so that it's no longer manual (file operations in Vectorscript are strictly limited to text files and are severely limited on what you can actually do to files). Python opens up a whole world of possibilities outside of the scope of Vectorscript because of its ability to import libraries. My current plan is to script in Vectorscript and then use PythonBeginContext to script in just what I need Python to do. The thing that makes Python a little harder to use in Vectorworks is that you are still limited to the Vectorscript function library to actually manipulate Vectorworks. Most of the time, it's taking the Vectorscript function and adding "vs." to the beginning of it. So, creating a rectangle in Vectorscript would look like Rect(p1.x,p1.y,p2.x,p2.y) and would look like vs.Rect(p1,p2) in Python. The other thing to keep in mind is about how Vectorscript and Python handle variables. Both are "typed" languages, meaning each variable has a defined variable type. What makes them different from each other is that VS is "statically typed" and Python is "dynamically typed." In VS, every variable MUST be defined as a variable type (string, integer, real, etc) and can only ever be that type. In Python, you can define a variable without assigning a type, Python will do that for you. Variables are also able to change their type within the code. So you can have a variable start as an integer (whole number only), then change to a floating point value (decimal number) when needed. This makes the language much more flexible, but also potentially dangerous if your code is sloppy. It also makes the code slower to operate, in that the "higher level" operations that the code does for you comes at the cost of computation time. While this definitely won't matter much in the scheme of Vectorworks plug-ins, it does matter when writing complex programs like mathematical solvers. Python is considered to be a "slow" running language that balances out by being very quick to write. If the programmer's time is more valuable than the computational time, then Python is the way to go. If you need the program to be snappy and can afford the cost of competent programmers, then it's best to use something like C++ which has virtually no hand-holding (manual memory management, garbage collection, etc), but is basically one step removed from assembly code and super fast to run. If you end up really getting into the weeds, the absolute best way to write plug-ins for VW would be to write in C++ using the SDK (software development kit) since you would have access to basically everything Vectorworks can do, but C++ is a much harder language to learn and definitely not what I would try to learn first. Quote Link to comment
willofmaine Posted October 25, 2021 Share Posted October 25, 2021 Okay! Sounds like I'll skip the C++ (not that I was considering it!...) and see what I can figure out with Python. And to that end, maybe what I'll do for starters is just forget about Vectorworks altogether and go learn some "regular" Python (by downloading the Python Interpreter and that "Mu" thing and whatever else). And then, just maybe, hopefully, the incorporation of Python into Vectorworks might make more sense to me. In the meantime, thank you for all of that information! Some of which is very helpful in choosing to tackle Python, and some of which I suspect I won't fully appreciate until I've spent some time with scripting. I'm looking forward to seeing what I can figure out... Thank you!! Quote Link to comment
Pat Stanford Posted October 25, 2021 Share Posted October 25, 2021 Learning a little Python outside of VW is probably a good idea. Make sure you learn a little about Libraries before you come back as Vectorscript is basically a Library you can add into Python scripts run inside of VW. 1 Quote Link to comment
willofmaine Posted October 25, 2021 Share Posted October 25, 2021 Great, I will do that, thank you! I think I'm about halfway there with Python, as I've got the Mu interactive shell doing math for me. Well, maybe not exactly quite halfway there... but, still, I've at least got it doing something! 1 Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.