Jump to content
Developer Wiki and Function Reference Links ×

Need help creating a Z Rotation script


Recommended Posts

I've never done any scripting before, only used scripts that others have created. I would like to know if it is possible to create a script that does the following things to all "Lighting Devices" in a file:

 

- Copy rotation data

- Enable "Set 3D Orientation" if it is not already enabled

- Enable "Z Rotation" if it is not already enabled

- Paste rotation data into "Z Rotation" field

 

If anyone could help me out with this I would truly appreciate it!

 

Thanks!

Link to comment

Yes, what you want should be possible. However, I am not a Spotlight user and I can't find where you "Enable Set 3D Orientation" or most of the rest so you will need to explain to me more clearly what you are actually trying to do and how you currently do it manually.

 

This would not be a bad script to learn on IF you want to learn to script.

 

If you don't want to learn that we call @Sam Jones and see if his Autopilot Tools already have this functionality.

 

  • Like 1
Link to comment

OK, I found it. I was looking in the completely wrong place.

 

The following script should do what you want for the first selected object on the active layer.

 

If it appears to work for you AND you want to learn more about scripting come back and we can talk about how to make it operate on all of the objects in the drawing.

 

Procedure LDRotation;

Var	H1:Handle;
	B1:Boolean;
	ORot:Real;
	
Begin
	H1:=FSActLayer;
	ORot:=HAngle(H1);
	SetRField(H1,'Lighting Device','Rotate3DPosition','True');
	SetRField(H1,'Lighting Device','EnableZRot','True');
	SetRField(H1,'Lighting Device','zRot',Concat(ORot));
	ResetObject(H1);
End;

Run(LDRotation);

 

  • Love 1
Link to comment

So I went ahead and tried my best to define each part of the script for my understanding and learning process:

(comments posted after each line)

 

Procedure LDRotation;

Var    
    H1:Handle; {defining H1 as your Handle}
    B1:Boolean; {defining B1 as your Boolean}
    ORot:Real; {definitely ORot as a real value? integer?}
    
Begin
    H1:=FSActLayer; {setting your Handle to be the first selected object on the layer}
    ORot:=HAngle(H1); {setting ORot to be the angle of the Handle or the first selected object on the layer}
    SetRField(H1,'Lighting Device','Rotate3DPosition','True'); {Not sure what the "R" between Set and Field is for, but enabling 3D Orientation on H1}
    SetRField(H1,'Lighting Device','EnableZRot','True'); {Enabling Z Rotation}
    SetRField(H1,'Lighting Device','zRot',Concat(ORot)); {setting the Z Rot field to be the ORot value}
    ResetObject(H1); {updates the object with the new Z Rotation value}
End;

Run(LDRotation);

 

The only two things that were unclear to me were the "H" in front of Angle and the "R" in SetRField. Thank you again for this script!

Edited by EBV_Nick
Link to comment

Answering the simple questions first:

 

HAngle is a Vectorscript (VS) Function (a subroutine that returns a value when it finishes. it must be assigned [:=] to a variable to accept the return value) that takes a Handle (H) [Handle: a numerical pointer to an object in a drawing file. Can change when the file is closed and reopened]. There are a series of functions for inquiring about objects that you can reference by a Handle.

 

SetRField is a VS Procedure ( a subroutine that does NOT return a value when it finishes. It can change things during execution, but does not have to be assigned to a variable.) It is an abbreviation for Set Record Field. Records are a type of database in VW. Each Record Definition consists of one or more Fields. SetRField is used to store a value into a Record.Field combination. You must know the name of both the Record and Field. PlugIn Objects have what is called the Parameter Record (that used the name of the PIO as the Record Name) that stores all the data you can enter in the OIP (Object Info Palette) (or the Settings dialog boxes) about the object.

 

Link to comment

There are lots of different ways to loop through multiple objects in a VW drawing and then do something to them. You can use a Repeat...Until loop (executes 1 or more times) or a While loop (executes zero or more times). But in these cases you have to manually change the handle to point to the next object you want to process.

 

I think in this case we are going to start with a different looping mechanism that hides most of the Handle handling and uses Criteria to define what objects to process. The command we are going to use is ForEachObject.

 

ForEachObject( callback:PROCEDURE;  c:CRITERIA) a

 

ForEach Object runs a subprogram (a procedure that takes a Handle to the object to process) one time for each object in the drawing that matches the Criteria. Criteria are a way of specifying what objects to handle. You can use multiple criteria like Layer, Class, Object Type, Selection State, Records attached. Record.Field values that match or don't match a given value.

 

So what we are going to do is take the script you have written above, convert it into the Procedure needed fro the ForEach Object procedure and set the criteria to what you need.

 

A user Procedure or Function is just a sub-program written in the script. It starts with a Procedure (or Function) line just like the main script and ends with an End; It does not get a separate RUN() line like the main script because it is called from within the script.  The following is an outline of how a script with user written Procedure would look like:

 

Procedure Main_Script;

Var	{Enter the names and types of any global variables you need in the script here.}
	{Variables must be declared in VS}

	Procedure Callback(H1:Handle);  {This defines the name of the procedure and says it needs to be passed a single Handle to run}
	
	Var {Local variables go here}

	Begin
		{Enter the code to do what the procedure needs to do here.}
	End;

Begin
	{This is the beginning of the code for the main script}
	{Do what needs to be done.}
	{the curly braces signify comments, but you already knew that}
	{the indentation above is not necessary, but I like it and think it makes it}
	{easier to read.}
End;  {end of the script code}

Run(Main_Script}

 

Now an exercise for the user:

 

Take the script posted by @EBV_Nick above and make it into a user procedure using the template above.

 

The body of the main script will be a single line:

 

ForEachObject(Callback,(((VSEL=TRUE) & (PON='Lighting Device'))));

This criteria limits the actions to a visible selected lighting devices. We can change the criteria later to handle more objects after we are certain the script is doing what we want it to do.

 

Ready, Steady, GO!!

  • Like 1
Link to comment

I finally figured it out @Pat Stanford! It took some dissecting of what was going on and some looking up of function but I finally puzzled it out.

 

Procedure Main_Script;

Var	
	H1:Handle;
	B1:Boolean; 
	ORot:Real;

Procedure Callback(H1:Handle);
	
Begin
	H1:=FSActLayer; 
	ORot:=HAngle(H1); 
	SetRField(H1,'Lighting Device','Rotate3DPosition','True'); 
	SetRField(H1,'Lighting Device','EnableZRot','True'); 
	SetRField(H1,'Lighting Device','zRot',Concat(ORot)); 
	ResetObject(H1);
	
	SetDSelect(H1);
End;

Begin
	ForEachObject(Callback,(((VSEL=TRUE) & (PON='Lighting Device'))));
End;

Run(Main_Script);

 

At first, I just copied the original script and used the template you gave me but I had some issues with the variables (still confused about the global vs. local variable portion of the template).

 

After I figured that out, the script compiled successfully so I tested it out and it was only working on the first light in the selection so I realized it must have something to do with the "FSActLayer" by only looping back and running on the same first selected Lighting Device. I tried to see if I could switch that to something else and then thought of just deselecting the completed light once the Procedure completed. I found the SetDSelect procedure and it worked like a charm. Very excited!

 

Thank you again!

Link to comment

Hi @EBV_Nick The SetDSelect is ingenious, but not the solution I had in mind.

 

I would have just removed the FSActLayer.

 

ForEachObject passes the handle to the object to process to Callback, so H1 already has the object to process so you don't need to assign the variable.

 

What you have now works great with the criteria we are using, but would fail if you changed the criteria to be objects that are not Visible and Selected. [VSEL] or even if they are visible and selected but not on the active layer.

 

Glad I was able to help. Ask again if things are not clear.

Link to comment

ForEachObject handles the Handles for you. 😉

 

Notice the definition of Callback(H1:Handle);  

 

What this means is that  the procedure has to be passed the handle to an object to be able to run.  So if your were going to "manually" call the procedure you would have to do something like Callback(HandletoMyObject); or else you would get an error.

 

Internally that is exactly what ForEachObject does. It makes a list of the handles of all the objects that match the criteria and then it calls Callback one time for each object passing the handle to the object as a parameter. So at the top of Callback H1 will contain the handle to the object passed by ForEachObject. The fact that you redefine what that handle points to does not matter to the code. It just knows that it called Callback with the handles it was supposed to use.

 

Clear?

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