Jump to content

Hello Community!

We will perform a system update on the Vectorworks Community Board on Friday, Dec 8th, from 3.00 PM to 6.00 PM EST. During this time, the site will be unavailable. I appreciate your patience.


  • Posts

  • Joined

  • Last visited

Posts posted by Sebastiaan

  1. 20 hours ago, Aiden said:

    No, I didn't use a saved set.


    The field I want to use "Channel Number" is selected/highlighted when I did this.


    Unsure how to fix this issue - only happens in certain drawings.

    Are these older drawings? In my files there is no “Channel Number” field. Just “channel” without the number. 

  2. 54 minutes ago, Aiden said:



    I'm having an issue where I go to channel number lighting symbols using the Spotlight Numbering Tool. Far too often I go to channel number lights using this tool and it doesn't work. Some drawings its fine, others it doesnt work. 


    I tick the Channel Number box and insert all the correct information. 


    I click on each light which highlights red.


    No channel number information is recorded/retained by the lighting symbol.


    If I manually select each light and in the OIP put in a channel number it works. 


    Is there something wrong with this tool?

    Are you using a saved set to recall your channel numbering setting? In this case there is a bug that sets the number of units per increment to zero. 

    also make duren that when adjusting the field you want to number. That this field is highlighted blue in de spotlight numbering window. Only the field that is highlighted will be adjusted. 

  3. What helped for me in some cases, not al unfortunately. 

    was to go into the edit  3d components of the truss symbol. And to move the geometry there for instance 1mm in 3D. This would force the geometry to appear again in OpenGL. Then I edited 3D again and moved the geometry back 1mm again. 

    hopefully this helps a little bit as a temporary workaround. 

  4. 9 minutes ago, EJ Berendsen said:

    I'm trying to make a 6 bar as done in the video. I can give each par64 his own channel number and patch. But I can not give each par 64 his own focus point. When I attach an focus point to one of the par's i get a red line indicating the focus direction from the centre of my 6 bar..

    I'm working in 2021 can this be a bug? 

    there is a new workflow for multicell fixtures in VW 2021. You can find explanation about the new function here. 

    https://app-help.vectorworks.net/2021/eng/index.htm#t=VW2021_Guide%2FLightingDesign1%2FConcept__Multi-cell_lighting_devices.htm&rhsearch=Multi cell&rhhlterm=Multi cell&rhsyns=

  5. Hi All,


    I am trying to get my head around manipulating accessories through Python scripts. Ultimately I would like to be able to position an accessory by a criteria such as the accessory name. I wonder if that is even possible as the function reference only seems to give handles to accessory index and not the name, but that is for a later step. 


    As a novice on scripting I am getting stuck on getting the GetAccPos3D & SetAccPos3D to do anything at all at this moment. 


    First I tried GetAccCount which worked instantly:


    crit = "((R IN ['Lighting Device']))" 	
    def callback(h):						
    	NumAcc = vs.LDevice_GetAccCount(h, 0)
    vs.ForEachObject(callback, crit) 		

    Then I tried GetAccPos3D, and the script seems to run but does not do anything. I tested the ForEachObject with a test string in an Alert dialog in the Callback, so I am sure that this does step through the lighting devices. Also I tried various combinations of the Accessory index and Cell index, but to no avail. My assumption is that a single cell lighting device would have cell index 0, and in the OIP I can see that the Accessory I am trying to manipulate has #2 as prefix before it's name in the dropdown. So I assumed that the accessory index is 2. Nonetheless I tried many other combinations as well. 


    Also I am uncertain on how to handle the fact that this function returns multiple values. 


    crit = "((R IN ['Lighting Device']))"    
    def callback(h):                       
        outRotation3D, outPosition3D = vs.LDevice_GetAccPos3D(h, 0, 2)
    vs.ForEachObject(callback, crit)         

    Would anyone be able to push me in the right direction?

  6. 11 hours ago, iswope said:

    Any luck with this? I have a similar need.

    For Universe and address field since VW 2020 there is the ‘Universe/Address’ Field that Automatically combines the two fields together with a separator. You can change the separator if you like in the spotlight preferences. 

    for other fields I recommend the AutoplotVW plugins. It has a menu command called ‘copy field to field’ that will do what you want. 

    • Like 1
  7. 1 hour ago, mercury2768 said:



    New Spotlight 2021 user here. I’m trying to add a container to my Channel number in my label legend manager but there’s no dropdown when I click the container section. It’s just stuck at none. Do I have to build these myself or am I missing some default ones like circle and oval and such that I need to get somewhere?

    There is no dropdown there. You need to click on the word none in the row of the field that you want to add the container to. Click until it reads the desired container name. 

    when you open the Label legend Manager for the first time 4 default containers are automatically added to your document ( circle, triangle, Rectangle and hexagon). They are placed as 2D symbols in a folder named Containers in the recourse manager. 

    if that is not the case in your file you could try to open a new file and open the LL manager and then import the created container folder with it’s contents to the file you are working in. 

    Also you can create containers yourself. If you crate a 2D symbol and place it in the folder named Containers, it will then become available to use in the label legend manager. The insertion point of the containers 2D symbol will be placed at the center point of the text field that you apply it to. 


  8. On 10/4/2020 at 10:58 PM, Pat Stanford said:

    Update. I THINK there is a bug and I have submitted it as such.


    Basically the idea behind DatabaseByScript is that you run a script and in that script you do whatever you want to determine what objects you want displayed in the database. You are not limited to the standard criteria. They can even be different types of objects. This functionality was originally added in VW2020 to allow Landmark users to generate a schedule that would display the Landscape Area name before the list of plants that are in that area.


    In VW2020 a Vectorscript command WSScript_AddHandle was added. Your DatabaseByScript script would figure out what objects to include and what order to include them in and then you would pass the handle to each object to the WSScript_AddHandle(YourHandle) and the database was created. Recalculate the worksheet and the script would run again.


    In VW2021, in addition to the AddHandle a new function WSScript_AddHandleId that lets you add an ID (that I don't know what it is used for) to the returned value also.


    But in the initial release (and the Beta of SP2), if you use AddHandle, or AddHandleId with an incrementing ID, only about 1/2 the desired items are returned. The workaround is to use WSScript_AddHandleId with a fixed ID.


    The script has been parameterized to let the user specify the Record name, the Field name, the minimum value to return and the maximum value to return. The Field should contain a string representation of an integer. The only error checking the script does it to make sure the Field for each object contains a valid number. If the field contains a valid number then it converts the string to an integer and checks if it is in the range of the min and max (inclusive). Any items that meet the range are returned in the database.


    Once you get the database sub-items defined you can use all of the standard worksheet functions to display information about the objects, Record.Field combinations, SUMmarize item and Sum Values.


    There appears to be another bug I have not had time to fully research yet, but it looks like the first item returned is not SUMmarizing even if the column you are SUMing on is the same as other rows. 


    I have attached a sample file showing both Lighting Devices and also 5 rectangles with a custom record/field combination of PTS.MKS that I was using for testing.


    Here is the script. Copy everything inside the Code block and paste into a new blank script in VW named 



    To enter the script convert a worksheet row to a database and accept whatever default criteria come up. Then right click on the database header row and choose Edit Database Formula. Enter the following to set a range of Lighting Device Channel numbers to display.


    =DATABASEBYSCRIPT('StringField_By_Range', 'Lighting Device', 'Channel', 4, 105)


    In the above, 4 is the Min channel to display and 105 is the Max channel. Change those two as you see fit. If you have other objects that have a numeric field stored as a string you can change the Record and Field names above to work with them.


    Procedure StringField_By_Range;
    {October 3, 2020}
    {©2020 Patrick Stanford pat@coviana.com}
    {Licensed under the GNU Lesser General Public License}
    {No Warranty Expressed of Implied. Use at your own risk.}
    {A sample script to show how to use the DatabaseByScript}
    {functionality in a worksheet to create your own objects when}
    {the standard criteria are not enough.}
    {This was originally developed to allow the generation of a}
    {subset of objects (Lighting Device) which had a field that was}
    {formatted as a sting, but the user was using as numeric data.}
    {The desire was to get a subset of the channels using a Min and Max}
    {value. Since the data was a string, a simple Greater Than or}
    {Less Than would not work.}
    {This script is run from the Database Formula Bar using a syntax of:}
    {=DatabaseByScript('StringField_By_Range', 'Lighting Device', 'Channel',}
    {    Min Channel Number, Max Channel Number)}
    {where Min Channel Number and Max Channel Number are Integers}
    {Procedure Execute does the heavy lifting. It converts the string}
    {representation of the number to an Integer. It then compares that}
    {Integer to the passed Min and Max Values. If the Integer is in}
    {the range then it adds the object to the database.}
    {The main body of the code only gets the parameters that are}
    {passed to the script and uses the passed Record & Field}
    {as Criteria in the ForEachObject procedure. ForEachObject}
    {gets a Handle for each object that matches the criteria}
    {and passes the handle to that object to the Execute procedure.}
    {As written, the only criteria is that the object has the}
    {passed Record (TheRecord) attached. The criteria in the }
    {ForEachObject line can be changed as necessary to return}
    {only the correct objects.}
    {The only error checking in this script is that the data in}
    {the field passes as TheField actually converts to a valid}
    {Do not operate heavy machinery or drive an automobile}
    {while using this script. If use causes excessive itching or }
    {unexplainable hair loss, discontinue use immediately and see}
    {a programmer immediately.}
    Var	CMax, CMin, CInteger: Integer;
    	TheRecord, TheField: String;
    	B1:	Boolean;
    Procedure Execute(Hd1:Handle);
    {Converts the value in TheRecord.TheField combination to a number}
    {If it is a valid number then it compares the data to CMin and CMax}
    {If the value is in the desired range, then add the object specified}
    {by Hd1 to the database}
    		B1:=ValidNumStr(GetRField(Hd1,TheRecord,TheField), CInteger);
    {AlrtDialog(Concat(Hd1,'  ',CInteger, '  ', B1,'  ',CMin,'  ',CMax,'  ',CInteger>=CMin,'  ',CInteger<=CMax));
    }		If (B1 & (CInteger >= CMin) & (CInteger <= CMax)) Then
    			{As of VW2021 SP2Beta1, AddHandle and AddHandleId used with}
    			{a variable ID only return a portion of the expected results}
    			{Using a fixed ID of 1 appears to return the correct items.}
    {			AlrtDialog(Concat(CInteger));} {AlrtDialog added for debugging}
    {Get the parameters passed top the script}
    {Record and Field are separate parameters because "escaping" the}
    {quotes properly to pass as a single Record.Field pair}
    {makes the script call almost unreadable}
    {Change the criteria in the next line to identify only the}
    {objects that any chance of being in the database. Additional}
    {criteria like, Layer, Class, In Symbol Definition, etc. would}
    {be typical. If you use the criteria builder, you probably}
    {want to edit the generated criteria string to use the variables}
    {TheRecord and TheField rather than hardcoded Record and Field}
    {names. This will provide additional flexibility for future use}
    {if you need to change the Record and field. They will only have}
    {to be changed in the DatabaseByScript call instead of editing}
    {the script.}	
    	ForEachObject(Execute, ((R IN [TheRecord])));

    Ask again where I have not been clear.


    Really interesting Pat! Thank you!


    I will now spend my time trying to actually understand what the code does. 

  9. 5 minutes ago, Sam Jones said:

    I just discovered it as a Worksheet function, not a VS function.  In VW Help, search for "Databasebyscript".  I am just investigating that documentation now.  Good Luck to both of us.

    Interesting! Although as I’ve only just plunged into the the world of scripting in VW, I might need some more practice until I attempt that! 

  10. 11 hours ago, Pat Stanford said:

    Yep, it looks like you can't use a Value command in a database formula.


    What might make your work around easier is to use Question Marks (?) as wildcards for a single character.


    =DATABASE((('Lighting Device'.'Channel'<='1?')) will return all of the object that have only two characters and start with the number 1.


    1?? will return all of the channels with three characters that start with the number 1.


    So instead of having to do ORs for 1 to 99 you could just do ORs for 1?, 2?, .... 9?.


    At least a little easier.


    VW2020 also added a new function called Database By Script that could be useful here. Let me see if I can make that work and I will post it.


    Good idea to use the wildcards. That might make it shorter indeed. I will look into that. I do want 100 to belong to the 1 -> 100 range, but that shouldn't be too hard to fit in. 


    I was trying to find some information on the database by script function and did not see much information about in. But I am curious what it is.

  11. 2 hours ago, MullinRJ said:

    Hi @Sebastiaan ,

       I'm seeing that. After too much trial and error, I've come to the same conclusion.


    Oddly, this works to show all 40 of the LDs'.

    =DATABASE((NOTINREFDLVP & NOTINDLVP & (PON='Lighting Device') & ('Lighting Device'.'Channel'>'0')))


    BUT, this does not work as expected:

    =DATABASE((NOTINREFDLVP & NOTINDLVP & (PON='Lighting Device') & ('Lighting Device'.'Channel'>'1')))


       It only shows LD's with channels 3-9, and 20. What I've noticed is that the DATABASE() engine is comparing strings, and not numerical values (as you'd like).

    Strings starting with "2xxx" through "9xxx" satisfy the equation, but strings "10" to "19" and "101" to "120" don't satisfy it because the first character in each string is a "1".


       You really need a VALUE() function, and that only appears to work in a worksheet cell, and not in a Database row.


       Sorry, I'm stumped.




    Yes I was guessing that too. It also kinda makes sense when you think of it. There is no cell to represent as value. The function does not change the original database and would have to create a new list of the fields as number values which obviously it doesn’t. 

    I already have the workaround so it is what it is. At least I now know it’s not just me. 

    thank you! 

  12. 3 minutes ago, MullinRJ said:

    @Sebastiaan ,

       Like Pat, I don't have a file to test this, but if a LD does not yet have a channel then this might work.


    =DATABASE( (NOTINREFDLVP & NOTINDLVP & (PON='Lighting Device') & ('Lighting Device'.'Channel'<>'') & (VALUE('Lighting Device'.'Channel')>=1) & (VALUE('Lighting Device'.'Channel')<=100)) )

    This expression checks for an empty channel string before it tests the values in the channel





    Hi Raymond,


    The issue is that I think that the value function does not work as expected when used in a DB formula. So your proposed formula does not do the trick either. 



  13. 8 hours ago, Pat Stanford said:

    Can you post a file with a few lights in it. I don't really have time to create a plot to play with, but I would be happy to play with the database criteria and see if we can make something work.


    Hi Pat,


    Of course, attached is a file with 40 lighting devices. 20 of them have the channel field filled with numbers from 1 to 20. the other 20 have numbers in the channel field from 101 to 121. 


    Very curious if this will work in a DB formula. 

    DB Formula Value Fun.vwx

  14. 5 minutes ago, Pat Stanford said:

    What happens if you edit your original formula to use just 100 without the quote marks around it? The Value statement should give you a number and you have to compare a number to a number.


    Also, does Lighting Device.Channel ONLY contain the "number"?  If there is anything other than characters 0-9 in the field, then the Value statement won't work. I THINK that even an extra space at the beginning or end will cause the Value to fail.


    I tried the formula below and this does not work either:

    =DATABASE((NOTINREFDLVP & NOTINDLVP & (PON='Lighting Device') & (VALUE('Lighting Device'.'Channel')>=1) & (VALUE('Lighting Device'.'Channel')<=100)))


    When lighting devices do not yet have a channel number assigned then the field will be an empty string (''). Would that cause a value function to fail too? That would be the only exception to a number in the text field. 


    I was already able to use the lengthy version in a script (with a variable in each of the 100 criteria and about 600 backslashes to escape the apostrophes ;-). So it works, but was curious if it could be shorter.

  15. Hi all,


    I am trying to make a database row based on Lighting devices and I want to set a criteria on the Channel field. In the lighting device record this is a text field.


    I want to set a filter to show only the lighting devices with a channel number between 1 and 100. But since it is a text field, the criteria field value '<=' and '>=' do not work. I tried to use a value function in the database formula but this does not work when I try it. Is it possible? Or am I doing it wrong? 


    This is how I tried to use the value function in the formula:

    =DATABASE((NOTINDLVP & NOTINREFDLVP & (PON='Lighting Device') & (VALUE('Lighting Device'.'Channel')>='1') & (VALUE('Lighting Device'.'Channel')<='100')))


    This way gives the desired result, but is a very long formula to edit:

    =DATABASE((NOTINREFDLVP & NOTINDLVP & (PON='Lighting Device') & (R IN ['Lighting Device']) & (('Lighting Device'.'Channel'='1') | ('Lighting Device'.'Channel'='2') | ('Lighting Device'.'Channel'='3') | ('Lighting Device'.'Channel'='4') | ('Lighting Device'.'Channel'='5') | ('Lighting Device'.'Channel'='6') | ('Lighting Device'.'Channel'='7') | ('Lighting Device'.'Channel'='8') | ('Lighting Device'.'Channel'='9') | ('Lighting Device'.'Channel'='10') | ('Lighting Device'.'Channel'='11') | ('Lighting Device'.'Channel'='12') | ('Lighting Device'.'Channel'='13') | ('Lighting Device'.'Channel'='14') | ('Lighting Device'.'Channel'='15') | ('Lighting Device'.'Channel'='16') | ('Lighting Device'.'Channel'='17') | ('Lighting Device'.'Channel'='18') | ('Lighting Device'.'Channel'='19') | ('Lighting Device'.'Channel'='20') | ('Lighting Device'.'Channel'='21') | ('Lighting Device'.'Channel'='22') | ('Lighting Device'.'Channel'='23') | ('Lighting Device'.'Channel'='24') | ('Lighting Device'.'Channel'='25') | ('Lighting Device'.'Channel'='26') | ('Lighting Device'.'Channel'='27') | ('Lighting Device'.'Channel'='28') | ('Lighting Device'.'Channel'='29') | ('Lighting Device'.'Channel'='30') | ('Lighting Device'.'Channel'='31') | ('Lighting Device'.'Channel'='32') | ('Lighting Device'.'Channel'='33') | ('Lighting Device'.'Channel'='34') | ('Lighting Device'.'Channel'='35') | ('Lighting Device'.'Channel'='36') | ('Lighting Device'.'Channel'='37') | ('Lighting Device'.'Channel'='38') | ('Lighting Device'.'Channel'='39') | ('Lighting Device'.'Channel'='40') | ('Lighting Device'.'Channel'='41') | ('Lighting Device'.'Channel'='42') | ('Lighting Device'.'Channel'='43') | ('Lighting Device'.'Channel'='44') | ('Lighting Device'.'Channel'='45') | ('Lighting Device'.'Channel'='46') | ('Lighting Device'.'Channel'='47') | ('Lighting Device'.'Channel'='48') | ('Lighting Device'.'Channel'='49') | ('Lighting Device'.'Channel'='50') | ('Lighting Device'.'Channel'='51') | ('Lighting Device'.'Channel'='52') | ('Lighting Device'.'Channel'='53') | ('Lighting Device'.'Channel'='54') | ('Lighting Device'.'Channel'='55') | ('Lighting Device'.'Channel'='56') | ('Lighting Device'.'Channel'='57') | ('Lighting Device'.'Channel'='58') | ('Lighting Device'.'Channel'='59') | ('Lighting Device'.'Channel'='60') | ('Lighting Device'.'Channel'='61') | ('Lighting Device'.'Channel'='62') | ('Lighting Device'.'Channel'='63') | ('Lighting Device'.'Channel'='64') | ('Lighting Device'.'Channel'='65') | ('Lighting Device'.'Channel'='66') | ('Lighting Device'.'Channel'='67') | ('Lighting Device'.'Channel'='68') | ('Lighting Device'.'Channel'='69') | ('Lighting Device'.'Channel'='70') | ('Lighting Device'.'Channel'='71') | ('Lighting Device'.'Channel'='72') | ('Lighting Device'.'Channel'='73') | ('Lighting Device'.'Channel'='74') | ('Lighting Device'.'Channel'='75') | ('Lighting Device'.'Channel'='76') | ('Lighting Device'.'Channel'='77') | ('Lighting Device'.'Channel'='78') | ('Lighting Device'.'Channel'='79') | ('Lighting Device'.'Channel'='80') | ('Lighting Device'.'Channel'='81') | ('Lighting Device'.'Channel'='82') | ('Lighting Device'.'Channel'='83') | ('Lighting Device'.'Channel'='84') | ('Lighting Device'.'Channel'='85') | ('Lighting Device'.'Channel'='86') | ('Lighting Device'.'Channel'='87') | ('Lighting Device'.'Channel'='88') | ('Lighting Device'.'Channel'='89') | ('Lighting Device'.'Channel'='90') | ('Lighting Device'.'Channel'='91') | ('Lighting Device'.'Channel'='92') | ('Lighting Device'.'Channel'='93') | ('Lighting Device'.'Channel'='94') | ('Lighting Device'.'Channel'='95') | ('Lighting Device'.'Channel'='96') | ('Lighting Device'.'Channel'='97') | ('Lighting Device'.'Channel'='98') | ('Lighting Device'.'Channel'='99') | ('Lighting Device'.'Channel'='100'))))


    Any thoughts?

  16. 50 minutes ago, Pat Stanford said:

    That is part of what makes this forum great. You have access to a number of nerds who have spent far too long digging into the depths of the documentation (and code) to figure some of this stuff out.


    I am looking at @MullinRJ, @Sam Jones, @JBenghiat. I apologize to all the rest of you who have helped me out over the years and am am drawing a blanks on right now.


    I think the programming community here for Vectorworks is probably the most helpful (and polite) group I have ever experienced.


    I am very happy that all of you are here!


    All of you have inspired me to follow an online Python course, and now I am trying to use that basic knowledge to make my own magic and it's going quite well!


    But I would never be able to, without all the helpful users,  information and example code in this forum!



  17. On 9/29/2020 at 5:54 PM, Pat Stanford said:


    def  vs.AddWSColumnOperator(worksheet, databaseRow, column, operatorType):

       return None


    With an operatorType of 2.



    The inverse function is vs.HasWSColumnOperator.


    I have no idea why these are named this way instead of using the standard Get and Set names.


    Sorry for the late reply, but thank you! This works well.


    No wonder I could not find it, not only is the naming convention different than the other functions, but also the sum values operatortype 2 is not explained in the developer page?



  18. Hi all,


    I'm taking my first steps in to Python scripting in Vectorworks. My first project is a worksheet script to create some database rows in a worksheet.


    What i could not find in the function reference is how to set the 'sum values' option for a column in a database row. Is there a script function for that?


    I found 'SetSprdSortSumColumns' to set summarize and sort, but could not see how to set 'sum values'.


    Thank you,



  19. 16 hours ago, MartinBlomberg said:

    Now I've found a lot of icons, thanks to the info given, cheers! But still, I lack a lot of tool icons and stuff, are they located some other place? 


    Some Icons are also hidden in individual plugin files in the plugin folder within the application folder.


    for instance many spotlight tool icons are hidden in spotlight.vwlibrary (richt mouse click 'show package contents' on a mac). Any .vwlibrary file could have some images in it, many don't but some do. A lot of work to check them all I know 😉


    Also there are a couple of icons that I couldn't find anywhere that where hidden somewhere deeper. In that case I made a screenshot of those.

  20. 12 minutes ago, MartinBlomberg said:

    Wow, awsome!! Thank you so much!


    May I ask, is there a way to get these icons from you, or can I extract them from the SD somehow? 





    You’re welcome.

    Individual tool icons can be found in the VW installation. Jim Wilson explained in this topic were they  can be found. I have not extracted the new 2020/2021 tool icons yet. So you would have to get them yourself. 

    Also in the topic below  you can learn how to get the toolset icons from a workspace file. 

    hope that helps you! 


    • Like 1
  • Create New...