Jump to content

what is the workflow for ensuring that drawing objects stay in the correct class?


Recommended Posts

Starting to work with other people on the same file, and noticing that things like crop objects, drawing labels, callouts etc, are ending up on a variety of different classes since some user are more cavalier about classing objects than others.  How can I make the work flow for these objects idiot proof?  I can create a class for each object, but I can't enforce that class usage...can I?

Link to comment

there oughta be a way, but I don't think there is. This has been to me and others, a matter of contention for many, many years. I want VWX to know that when I Insert a camera object (for example) it should go into the camera object class.


It does not.

There is a way, in the Plug In Manager, to edit some PIOs and force classing, but that configuration is lost when there is an application update.

  • Like 1
Link to comment

@Kevin Allen yes some sort of tool mapping would be ideal. Years ago I recall someone telling me they put all drawing objects into symbols that exploded into groups into a resource folder, so they would never use the tool button for those objects again.  Sounds like an idiot proof method, but I don't want to keep looking over to the resource folder everytime I want to place a callout.

Link to comment

@line-weight what a labor of love and frustration!  



The custom modification tool does not work (I've run it thru tech support, they acknowledge the bug) on all items.

Custom tool command does.....not really create custom tools with these objects.  

I have a custom script that forces the class of a few of these items.  That seems to be a workable solution.  


Does anyone else have any workflow ideas?

Link to comment

Seriously, there are ways to help automate classing (I am not enough of an expert to be able to offer the best ways as I work almost exclusively solo), but it is going to be very hard to "force" everyone to do the right thing. When they feel rushed they are going to do what they think is fastest, regardless of the issues that causes down stream.


I think @michaelk has a bunch of worksheets that he uses to audit drawings and show things that are in the wrong classes. Maybe something like that would help for you?

  • Like 1
Link to comment
4 minutes ago, Pat Stanford said:

When they feel rushed they are going to do what they think is fastest, regardless of the issues that causes down stream.

That hits the nail on the head.


I deal with this constantly.  Not everyone was trained with the correct "drafting ethics", and for guys like us who were, it can be very frustrating.  The only way to go is to set up drafting standards and get everyone trained on those standards.  Get the Principal/CEO in involved and on board with enforcing drafting standards.  

  • Like 1
Link to comment

@Rolan Castaneda I am fully onboard with your sentiment.  I'm that type of person where even if I KNOW that the miss-classed object is not going to affect the final outcome, I feel compelled to change it.  


That being said, I am also wondering why in this day and age vw cannot allow us to map objects to classes as we see fit?  Is that what auto-classing does in the architect version? 


Link to comment

I was pointing out the menu commend that Jesse wrote.  


For example. Using Jesse's menu command, here's a list of all the objects - including objects inside wall comments and symbol definitions! - in the drawing I'm working on now that are in the Demo class.


You can go to an object straight from the list or create a worksheet.


I'm not as good as Jesse at creating cool dialog boxes.  So in the past I've just made my own worksheets and changed the criteria manually to discover how many walls got put into the class Site-DTM-Modifier.

  • Laugh 1
Link to comment

I deal with this a lot doing venue drawings with fairly complex class structures.  Often these venues are in educational institutions where the students may not have a firm grasp of classes vs. layers, so I do as much as I can to "idiot-proof" the drawings before handing them over.  This is pretty easy to do with symbols, since you can set the Assign to Class attribute in the Symbol Options, but that doesn't work with plug-in objects.


I think it would be a grand idea for there to be a way to setup default class mapping per PIO, but it would most certainly have to be drawing specific since you might not have the classes in your current drawing.  Though I could also see a world in which you could set up the default class attributes and have Vectorworks build the class for you if it doesn't currently exist in the drawing.


This would have to be a something that VW adds in the long term, but I wouldn't hold your breath for it.  In the short term, it wouldn't be too much work to script up a dialog box that would populate a list of PIO types found in the drawing and let you map a class to them.  Then, the script would scour the drawing and change all existing PIOs to their mapped class.


I could write such a plug-in pretty quickly, so if I wrap up the drawing I'm currently working on, I might be able to put something together for you later this afternoon.

  • Like 2
  • Love 2
Link to comment

I was just having a conversation about this recently.


I wrote this script for someone else.  It creates/updates classes AND their descriptions in a VW drawing.  If you hover over a class in the Nav Palette and the class has a description, that description will pop up.  So you can have a description of a class that says "This class is for plumbing fixtures only.  NOT windows.  NOT lobby furniture!"


Run this script and it will create classes and create/update their descriptions.  It will NOT delete existing classes.


I think it will NOT make anyone check the descriptions, but you will know that you tried.


PS. I've always wanted an option to have the screen flash red whenever creating objects while NOT in the None class.  


And an option to define classes, like the None class, that the Visibility Tool Ignores when the mode is set to invisible.

Create Classes From Worksheet v2024.vwx

  • Like 1
Link to comment

@michaelk "I have a bunch of old worksheets"


Probably shortly after I found all of your posts about worksheets, and scripts to improve formatting, I started adding three columns in almost every worksheet:

Symbol/type, layer, and class.  Always in a kinda grey as a house keeping note.  "=FIRSTNONEMPTY(SYMBOLNAME, OBJECTTYPENAME)" for the symbol list - all in a way to reveal where we went wrong!



Thanks for the script!  This will save some time for sure!




  • Like 1
Link to comment

@michaelk I think I told you when we met up last spring that I use GOTO statements often in my code as quick escape sequences since Pascal doesn't have a more traditional BREAK command (happy to be wrong about this, of course).  It's used often in this particular script since the script has to traverse every single object in every single Symbol, Group, and Wall searching for objects of the target class.  It uses the standard WHILE loop using FInGroup and NextObj, but if it finds an object using the class, it doesn't need to keep searching that object, so I use a GOTO statement to exit the WHILE loop.  It doesn't save a huge amount of time or computational power, but if you run the command on a huge drawing with complicated symbols, it will be noticeable.


However, that won't throw the error you're seeing since I'm not using a FOR or CASE structure in that example.  In this script, I am using a GOTO in each.  For the FOR loop, I'm using it to return the object type constant of a given parent object type name.  I have an array of strings that is indexed by the object type constant selectors so that I can populate the Object Type and Parent Type columns of the dialog box.  When you click on the Go to Selected button, it feeds the string found in the Parent Type column into a function that will then spit out the object type constant used in a CASE statement to determine how to get to the chosen object.  That function is really simple and looks like this:


FUNCTION GetObjectTypeIndex(objName:STRING) : INTEGER;

{Searches object types for matching string and returns Object Number}

		99; {Escape Sequence}

		IF(objName=sMiscResourceManager) THEN
				GOTO 99;
		FOR i:=1 TO kNumTypes DO
				IF(objName=objTypes[i]) THEN GOTO 99;
		99: GetObjectTypeIndex:=i;


If it gets fed in "Resource Manager" as the parent, it will return 999 since the Resource Manager doesn't have an object type.  I don't know for the life of me why I chose to use the GOTO to skip the FOR loop since I could have just put the FOR loop into the ELSE of the IF, but I did and it works, so I'm sticking by it.  In the FOR loop, once it finds the match it doesn't need to complete the loop so instead it uses GOTO 99 to exit out.


As for using a GOTO in a CASE structure, I wrote in a way to rebuild the list browser anytime you change target class or any of the Search options.  The dialog handler is a big event CASE structure, and I have a LABEL in the part of the SetupDialogC event that adds and fills out the list browser.  Anytime the user changes the class or the Search option, the list browser data is wiped out and a GOTO statements returns to that LABEL and regenerates the list browser.  It's the best way I've found to be able to quickly regen the list browser without copying and pasting the generation code in each event that would require a rebuild.


As penance for @grant_PD for hijacking their thread with nonsense, I'll get to writing up that command now.

  • Like 4
Link to comment

All done.  Here you go, lightly tested in VW2023 and VW2024:




@michaelk I noticed in your screenshot that the two columns UUID and Parent UUID are visible.  These are supposed to be hidden (have a column width of 0), did you expand the columns or is that how it presents on Mac?  I'm asking because this plug-in will also use a hidden column to conceal the record name for each plug-in object so that it instead presents the localized name.  If the Record Name column is visible when you run this, let me know and I'll change up how the programming works a little bit.


To install this plug-in, follow the steps below:

  1. Download the attached Reset Plug-in Obj Classes.vsm file
  2. Open your Vectorworks User File in a file explorer / Finder window
    1. Easiest way to do this to go to your Vectorworks Preferences, select the User Folder tab, and click on the Explore (Windows) or Open in Finder (Mac) button
  3. Open the Plug-ins folder
  4. Place the downloaded Reset Plug-in Obj Classes.vsm file into the Plug-ins folder of your User Folder
  5. Restart Vectorworks
  6. Put the new plug-in into your workspace
    1. Go to Tools - Workspaces - Edit Current Workspace
    2. Select the Menus tab
    3. In the box on the left, find and expand the category JNC
    4. In the box on the right, find a menu to place the new command in, such as Edit or Modify or Tools
    5. Click and drag the Reset Plug-in Obj Classes command from the box on the left to the target menu in the box on the right
    6. Click OK

I tested this and it seemed to work correctly.  As a quick side note, as part of the process it will reset the objects after changing their class, so if you have objects that take a while to reset or a lot of objects will be affected by this, the operation may take a while to complete.  Just a heads up.  In my testing it was pretty fast, however.


Reset Plug-in Obj Classes.vsm

Link to comment
36 minutes ago, michaelk said:

I like your GOTO method! 

You would love my method filtering duplicates when building dynamic arrays.  I use a FOR loop to go through the existing array with the code to add a new item to the array placed after the FOR loop and a LABEL pointer set at the very end.  Inside the FOR loop, if a matching item is found, it uses a GOTO statement to bypass the code adding to the array.  If it reaches the end of the loop without finding a match, it is allowed to get to the addition code.


Here's the code in this plug-in that builds the array of object types using a ForEachObject(BuildTypeArray,(INSYMBOL & INVIEWPORT & (T=PLUGINOBJECT))) call:



{ForEachObject callback that builds array of object types}

	LABEL 99; {Escape}

		FOR i:=1 TO numPIOTypes DO
				IF(PIOName = PIOTypes[i].name) THEN
						PIOTypes[i].num:=PIOTypes[i].num + 1;
						GOTO 99;
		numPIOTypes:=numPIOTypes + 1;
		ALLOCATE PIOTypes[1..numPIOTypes];
		IF(locName <> '') THEN PIOTypes[numPIOTypes].locName:=locName ELSE PIOTypes[numPIOTypes].locName:=PIOName;
		99: {Escape}


  • Laugh 1
Link to comment

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.

Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...