Jump to content

Spotlight: Insert a lighting device


Recommended Posts

We get data from Calculux, in CSV format:

 

image.png.03ee72fa7f8e612d627e1fff563dda0a.png

 

The requirement is to automatically populate a drawing with lights.

 

The 'Qty and Code' field is a reference to a key. For example, in this case 'D' could be any sort of light; a flood, a spotlight, a wash, made by any manufacturer. Assuming it is possible to associate the key to a lighting device in the Resource Manager, is it possible to insert a Lighting Device (as if one were using the Lighting Device Tool) programmatically?

 

I'm looking at the documentation of 'VS:CreateLight' but it's not exactly exhaustive.

Link to comment

I am not a Python nor a Spotlight guy, but what you want should be possible.

 

The function you probably want to insert a Spotlight Instrument is probably CreateCustomObject. You will then need to use the data from Calculux to set the Parameter Record fields to do what you need.

 

Hopefully some or our great Spotlight scripting gurus ( @JBenghiat @Sam Jones) will see this and tell us both how to actually accomplish what you want.

Link to comment

That's how you do it.

CreateCustomObject('Lighting Device', X, Y, RotationAngle);

but it's going to need more info than is in the worksheet you show.  It is likely you will need to either by hand or by script transfer the information from the worksheet you show to one that will then have all you need and that you will read the values from.

 

Get the handle to the fixture you just placed with

CreateCustomObject('Lighting Device', X, Y, RotationAngle);

 

NewLight := LNewObj;

 

You are going to need way more info in your worksheet, because you need to set the parameters of the Lighting Device, and you will need to set fields in your code that the "Lighting Device Tool" would normally pull from the symbol selected.  At a minimum you will need the Symbol Name of the fixture you want to place.  You can then go into the symbol definition and pull some of the information from the "Light Info Record" attached to the symbol definition.  This all assumes that the needed symbols are already in the document.

 

There will be information you want to set that is not in the "Light Info Record" that had better be in your worksheet.  Getting the correct symbol name from the key referenced by the 'Qty and Code' column seems unlikely so you would have to reference some translation file or worksheet.

 

If you have the information, setting the parameters is straight forward.
SetRField(NewLD, 'Lighting Device', 'Symbol Name',  'Light Instr Martin MAC Viper Profile');
SetRField(NewLD, 'Lighting Device', 'Inst Type',  'Martin MAC Viper Profile');


SetRField(NewLD, 'Lighting Device', 'Fixture Mode',  'Martin Mac Viper Profile Basic');
SetRField(NewLD, 'Lighting Device', 'Fixture Mode',  '1225W');  

{Etc, etc, ...}

 

I'm not sure what the values in your Switch Mode columns are, but you would need to figure that out and send the values to the correct parameters.

 

Lastly,
ResetObject(NewLD);

 

None of this is rocket science, but it is a rather involved script that would be broken by entries in the Calculux worksheet that you did not match correctly/exactly.

Where does the Calculux table come from?  Maybe there is better way to get the information.  Probably not, but maybe.

How badly do you want the functionality you describe?  You might aim lower by making a script to mark the locations with loci or a symbol and then placing the lights by hand with the Lighting Device Tool.

 

It would be nice to use CallToolByName() in your script, but doing that with the Lighting Device Tool makes you click on locations to place the lights.

Link to comment

If I understand you correctly, the answer is that it isn't possible to insert a Lighting Device (as if one were using the Lighting Device Tool) programmatically.

 

I had hoped for some equivalent of (cue ghastly pseudo code):

 

    LightingDeviceRecord LDKeyRecord = GetFromResourceManager (LightKey[x])

    LightingDevice NewLD = PlaceLightingDevice (LDKeyRecord , X, Y, Z)

    NewLD.Tilt = a1

    NewLD.Pan = a2

    NewLD.Dim = etc etc etc...

Link to comment

The functionality you originally described is possible, I think, but it is way more involved to code, and it all hinges on the correct exact name of the symbol you need being stored in Lightkey[x].  If you jump that hurdle, you have to:

Build a resource list

Scan the list for the symbol name

Go into the symbol definition to read values you need like Instrument Type (true name Inst Type) from the Light Info Record attached to the symbol definition, and do all the steps mentioned above.

So, (pause here and take a breath), how badly do you need the functionality?  What you need to do is not rocket science, but it is way more involved than what you were hoping for.

Kind of an interesting problem actually, but everything hinges on having LightKey[x] provide the exact symbol name.  You might make a translation table of LightKey to symbol name, but that is just another step and want that would need to be maintained.

 

BTW:

NewLD.Tilt = a1

NewLD.Pan = a2

just translates to

SetRField(NewLD, 'Lighting Device', Tilt, a1);

SetRField(NewLD, 'Lighting Device', Pay, a2);

Link to comment

Thank you for the response, but I'm still somewhat confuzzled.

My question is simply, "If I can get a reference to a lighting device in the resource manager, can I insert said lighting device programmatically?"

Getting the reference, associating it with a key etc etc are all currently under the job code SEP. 🙂

Link to comment
9 hours ago, kevin.hayward said:

Thank you for the response, but I'm still somewhat confuzzled.

My question is simply, "If I can get a reference to a lighting device in the resource manager, can I insert said lighting device programmatically?"

Getting the reference, associating it with a key etc etc are all currently under the job code SEP. 🙂

The simple answer is, yes, this is definitely possible.

 

Also, we're assuming you mean a Spotlight Lighting Device object and not a rendering spotlight. (Both are possible).

 

You would use vs.CreateCustomObject() to insert a Lighting Device at the desired location and orientation, vs.HMove3D() to set the z location, and then set the Lighting Device fields for pan, tilt, and which symbol to use. 

 

The least straightforwards element is mapping the key value (e.g. "D") to the name of the symbol you want to use for the lighting device. You can hand-code a dict, read from a worksheet, attach a record to the symbol, etc.

Link to comment
55 minutes ago, JBenghiat said:

The least straightforwards element is mapping the key value (e.g. "D") to the name of the symbol you want to use

If you want to use symbols from the VW Resource Manager you would need to do some kind of table look up to match "D" to symbol name, and you would need to get a resource list ID, "BuildResourceList()" or "BuildResourceList2"().  Then you would need to iterate through the list to find a name in the table that matched what was considered equivalent to the "D" symbol.  Retrieve that symbol and place it.  After that, you fill in the fields that you need to fill in.  There are some variations to this, but nothing much simpler.

Link to comment
4 minutes ago, Sam Jones said:

If you want to use symbols from the VW Resource Manager you would need to do some kind of table look up to match "D" to symbol name, and you would need to get a resource list ID, "BuildResourceList()" or "BuildResourceList2"().  Then you would need to iterate through the list to find a name in the table that matched what was considered equivalent to the "D" symbol.  Retrieve that symbol and place it.  After that, you fill in the fields that you need to fill in.  There are some variations to this, but nothing much simpler.

@Sam Jones why not just use vs.GetObject() to get the symbol definition by name and vs.GetTypeN() to confirm that it's a symbol definition? Then all the Lighting Device needs it the name of the symbol. 

Link to comment
1 minute ago, JBenghiat said:

why not just use vs.GetObject() to get the symbol definition by name and vs.GetTypeN() to confirm that it's a symbol definition? Then all the Lighting Device needs it the name of the symbol

I  would assume that if the symbol desired is not in the document that "GetObject()" would fail.  If he has already loaded the needed symbols into the document, then, absolutely, GetObject() is the way to go.  If he needs to get it from another file, I think he needs to build a resource list.  No?

 

Link to comment
16 hours ago, Sam Jones said:

How would you know the code,  "1*D", represented any Lighting Device in you resource manager?

 

As I said, for the moment linking the key to an actual lighting instrument resource is SEP (probably future me, but he'll just have to suck it up). The rough plan is to populate an array with the key+reference and have the user select (via dialog) the relevant lighting devices from the resource manager, but I'll burn THAT bridge when I come to it.

 

14 hours ago, JBenghiat said:

The simple answer is, yes, this is definitely possible.

 

Also, we're assuming you mean a Spotlight Lighting Device object and not a rendering spotlight. (Both are possible).

 

You would use vs.CreateCustomObject() to insert a Lighting Device at the desired location and orientation, vs.HMove3D() to set the z location, and then set the Lighting Device fields for pan, tilt, and which symbol to use. 

 

The least straightforwards element is mapping the key value (e.g. "D") to the name of the symbol you want to use for the lighting device. You can hand-code a dict, read from a worksheet, attach a record to the symbol, etc.

1. Huzzah!

 

2. Yes, a Spotlight Lighting Device.

 

3. CreateCustomObject? From something Sam said upthread, I got the impression that I'd have to manually populate all the relevant lighting instrument information (power, weight, etc) with a 'custom object'.

 

4. Nah. Sounds too much like hard work. 🙂

 

Sam mentioned building a resource list. Surely that is what the resource manager is? A central source for ALL the information about a lighting instrument.

 

I did try inserting a lighting instrument to an empty drawing and exporting to text. Unfortunately (as far as I can tell), calls to the resource manager aren't recorded. It reads as though the lighting instrument were created entirely WITHIN the drawing (as in, the way the commands are exported) with no external references (again, as far as I can tell).

 

Thank you both for helping, genuinely. This is kinda frustrating because it should be relatively straightforward. After all, VectorWorks can insert references from the resource manager and populate all the data with only two clicks.

Link to comment

The Resource Manager is the human usable version. To do anything with a script you have to use the scripting language CreateResourceList commands to get a list of resources of the specific type. If you want the user to choose which one, you have to do dialog boxes to display the data. 

 

There is no way to pick an item in the Resource Manager and then run a script that says use the object selected in the RM. 

 

😞

Link to comment
8 hours ago, kevin.hayward said:

Unfortunately (as far as I can tell), calls to the resource manager aren't recorded. It reads as though the lighting instrument were created entirely WITHIN the drawing (as in, the way the commands are exported) with no external references (again, as far as I can tell).

I'm not entirely sure what you mean here. As Pat remarked, the Resource Manager is only an interface for working with resources. The Lighting Device accepts the name of a symbol (a resource), and copies the geometry of the symbol to the Lighting Device. Lighting Devices also take default data from the symbol on insertion, which you can mimic via script by calling vs.ApplyLightInfoRecord().

 

An "external reference" in Vectorworks lingo would mean that you are referencing a symbol in another file. Is that what you mean, or are you only trying to determine the connection between the Lighting Device and the Resource Manager. Mapping to a symbol outside of the current drawing file would be where Sam's RessourceList comes in.

 

The following script will add the first row as described, assuming that "D" maps to a symbol named "My Light." It also assumes that the symbol exists in the current drawing. The neutral orientation (pan=0) is towards the top of the page. You can set a different initial orientation with the final parameter in CreateCustomObject().

symbolName = 'My Light'

hNew = vs.CreateCustomObject('Lighting Device', (-61,-7.55), 0)
vs.Move3DObj(hNew, 0, 0, 11.5)

vs.SetRField( hNew, 'Lighting Device', 'Symbol Name', symbolName)
vs.ApplyLightInfoRecord(vs.GetObject(symbolName), hNew)
vs.SetRField( hNew, 'Lighting Device', 'Pan', '-7')
vs.SetRField( hNew, 'Lighting Device', 'Tilt', '46')

vs.ResetObject(hNew)

 

Link to comment
13 hours ago, JBenghiat said:

are you only trying to determine the connection between the Lighting Device and the Resource Manager. 

 

 

Yes. I was looking to see how VW does it to see if I could get a better idea.

 

13 hours ago, JBenghiat said:

The following script will add the first row as described, assuming that "D" maps to a symbol named "My Light." It also assumes that the symbol exists in the current drawing. The neutral orientation (pan=0) is towards the top of the page. You can set a different initial orientation with the final parameter in CreateCustomObject().

(emphasis mine)

 

The idea is to automate the placement of dozens of lights for sporting events. It's time consuming and prone to error, people get bored.

Explicitly importing the desired lights BEFORE running the script? A coupla minutes at most in service of saving hours of grunt work? I can live with that.

 

Thank you all for your time and input.

 

Now I just have to work out building ResourceLists, but that's a question for another thread...

 

if only VectorWorks had heard of this new cool trick called, wait for it, "documentation". 😄

Link to comment
  • 2 weeks later...

One hates to be all necromantic 'n' stuff but...

symbolName = 'My Light'

hNew = vs.CreateCustomObject('Lighting Device', (-61,-7.55), 0)
vs.Move3DObj(hNew, 0, 0, 11.5)

vs.SetRField( hNew, 'Lighting Device', 'Symbol Name', symbolName)
vs.ApplyLightInfoRecord(vs.GetObject(symbolName), hNew)
vs.SetRField( hNew, 'Lighting Device', 'Pan', '-7')
vs.SetRField( hNew, 'Lighting Device', 'Tilt', '46')

vs.ResetObject(hNew)

 

doesn't appear to be working exactly, yet.

Don't get me wrong, you've got me this far and I am very grateful, and any problems are on my end.

 

So when I run my script (including a nice little snippet of code I *ahem* 'borrowed' to populate a popup box) I only get simple boxes. There's lighting data attached, but it's all at default values.

 

The problem:

  1. The script doesn't create the correct graphical symbol
  2. The script doesn't add the correct lighting instrument information

Part of it is wrapping my head around how VW works with 'intelligent' symbols. In AutoCAD, a block is a graphical object that has a data attached (in the form of attributes).

As far as I can see, a VW 'lighting device' (and similar) is a data that has a graphical symbol attached.

My thinking is to get a reference to the definition of the lighting device, then extract the references to the symbol and data:

LuminaireList, LuminaireCount = vs.BuildResourceList(16, 0, "")
deviceHandle = vs.GetResourceFromList(LuminaireList, 0)
symbolName  = str(vs.GetRField(deviceHandle, 'Symbol Name'))

 Am I heading in the right direction?

Link to comment

There was a change made to the Lighting Device object in VW2021 that necessitates an additional field for setting the symbol, "Symbol Definition".  What your code is missing is:

vs.SetRField( hNew, 'Lighting Device', 'Symbol Definition', symbolName)

 

You now need this in addition to the Symbol Name field.  As for the data, you are using the ApplyLightInfoRecord procedure correctly, so I'm not sure if it's tied to the same problem or if there is a bug with the Python implementation of ApplyLightInfoRecord.  This should apply the data found in the Light Info Record attached to the passed symbol to the Lighting Device object (I can surely say that it works in Vectorworks scripts that use it).  If the data isn't coming through, verify that the Light Info Record is indeed attached to the symbol and has the correct information.

 

For your luminaire list, your snippet with vs.BuildResourceList is a good start, but it's going to include every symbol found in the drawing to your list regardless of whether the symbol has a Light Info Record record format attached.  In my scripts that need a list of fixtures found in the current drawing, I start with the BuildResourceList but then comb through that list and create an array of symbol definitions that have the Light Info Record attached.  Keep in mind that this does require a nested loop to scan each attached record format, as lighting fixtures commonly have more than one attached.

 

Here's a function that I have in one of my scripts that does this.  It's in Vectorscript, but you should be able to get the idea.  It scans the given symbol and if it finds a Light Info Record, it adds the symbol name to the global array fixtureDefs (Vectorscript does not allow you to return dynamic arrays in a function).

 

FUNCTION GetFixtureDefinitions : INTEGER;

{Builds array of fixture definitions and returns number of definitions}

	CONST
	
		kSymbol = 16;
	
	VAR
	
		i,j,counter:INTEGER;
		resList,numItems:LONGINT;
		symDef:HANDLE;
		recordCheck:BOOLEAN;
		symName:STRING;
	
	BEGIN
		counter:=0;
		
		resList:=BuildResourceList(kSymbol,0,'',numItems);
		
		FOR i:=1 TO numItems DO
			BEGIN
				symDef:=GetResourceFromList(resList,i);
				recordCheck:=FALSE;
				FOR j:=1 TO NumRecords(symDef) DO IF(GetName(GetRecord(symDef,j)) = 'Light Info Record') THEN recordCheck:=TRUE;
				IF(recordCheck) THEN
					BEGIN
						counter:=counter+1;
						symName:=GetNameFromResourceList(resList,i);
						ALLOCATE fixtureDefs[1..counter];
						fixtureDefs[counter]:=symName;
					END;
			END;
		
		GetFixtureDefinitions:=counter;
	END;

 

Link to comment

heres another take on how i insert lighting devices for a stage wash plugin i built.... 

 

def placelights():
  cur_lights = []
  vs.Symbol(symbolName, x, y, -22.5)
  last = vs.LNewObj()
  vs.Move3DObj(last, 0, 0, z_location - 3)
  vs.ResetObject(last)
  cur_lights.append(last)
  vs.DSelectAll()

  for i in range(len(cur_lights)):
    vs.DSelectAll()
    vs.SetSelect(cur_lights[i])
    vs.DoMenuTextByName('Convert To Instrument',0)

 

although i didn't know vs.ApplyLightInfoRecord() existed at the time. lol 

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.

Guest
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...