Jump to content
Developer Wiki and Function Reference Links ×

All objects in file script


lcda

Recommended Posts

It depends on what you mean by "ALL" objects, but basically, yes. You can use a script with a criteria of All Objects and effect everything in the file.

 

Sample1 below will set the Line Weight and Line Color to ByClass fall all objects in the drawing, including objects in Symbols, PIOS, and Viewport Annotations.

Procedure Sample1;

Procedure Execute(Hd1:Handle);
	BEGIN
		SetPenColorByClass(Hd1);
		SetLWByClass(Hd1);
	End;
	
BEGIN
	ForEachObject(Execute, (INSYMBOL & INOBJECT & INVIEWPORT & (ALL)));
End;

Run(Sample1);

 

You can use a similar format and just change what is inside the Execute procedure to make other changes.

 

Use the Criteria Builder in the Script Editor to change the criteria if you don't actually want to do EVERY object in the drawing.

 

To change all objects to Screen Plane the line inside of Execute would be:

 

SetObjectVariableBoolean(HD1, 1160, True);

 

For Layer Plane

SetObjectVariableBoolean(HD1, 1162, True);

 

 

Ask again as you have more questions.

 

HTH

 

Link to comment
{///////////////////////////////////////////
UseClassAttribs
(c) 2001 Nemetschek North America. Distribute freely.

Shows how to set object to use display attributes of assigned class.

///////////////////////////////////////////}


PROCEDURE UseClassAttribs;
VAR
	h : HANDLE;

BEGIN
	{ get a handle to the object }

	h:= FSActLayer;

	{ set the object to use the class settings for }
	{ its display attributes.                      }

	SetFillColorByClass(h);
	SetPenColorByClass(h);
	SetFPatByClass(h);
	SetLWByClass(h);
	SetLSByClass(h);
END;
Run(UseClassAttribs);

  I made this script years ago a thin in 2016 version but I wish it could be for all objects and also render by class

Link to comment

I don't understand "Render By Class". Do you mean Texture?

 

The script you posted sets the defaults for the file so that all new objects are drawn using those ByClass attributes. It does not effect any objects that have already been drawn. For that you need to use the object specific equivalents in the Execute procedure I provided above.

 

 

Link to comment

ok I think it's working now I just need the instruction to change layer plane and render texture by class

 

Procedure UseClassAttribs;

Procedure Execute(Hd1:Handle);
	BEGIN

	SetFillColorByClass(Hd1);
	SetPenColorByClass(Hd1);
	SetFPatByClass(Hd1);
	SetLWByClass(Hd1);
	SetLSByClass(Hd1);
	SetOpacityByClass(Hd1);
	
	End;
	
BEGIN
	ForEachObject(Execute, (INSYMBOL & INOBJECT & INVIEWPORT & (ALL)));
End;

Run(UseClassAttribs);

 

Edited by lcda
Link to comment

The script to change all screen objects to the layer plane is listed below:

 

PROCEDURE ScreenToLayer;

PROCEDURE Execute(h:HANDLE);

	BEGIN
		SetObjectVariableBoolean(h,1160,FALSE);
	END;

BEGIN
	ForEachObject(Execute,(PLA='Screen Plane'));
END;

Run(ScreenToLayer);

 

VERY IMPORTANT IN THIS CASE:  Do not put the INSYMBOL and INOBJECT flags in the criteria for the ForEachObject call.  Vectorworks uses the screen plane to determine which objects exist within the 2D component of hybrid symbols and plug-in objects.  So, if you include those flags, all of your hybrid symbols will be turned into 3D only symbols, and plug-in objects that contain 2D and 3D geometry will project the 2D geometry into 3D space.  You don't need the INVIEWPORT call because annotations ignore the plane anyway.

 

As for ObjectVariable 1162, "Object is in Layer Plane", it is read-only, so using SetObjectVariableBoolean(h,1162,TRUE) won't do anything.

 

EDIT:  Looking back over this post, I'm a little confused about what you are looking for.  Are you looking to force things onto the Screen Plane or taking objects existing on the Screen Plane and forcing them to Layer Plane?  If you are looking to force all objects to the screen plane, you can use the code below:

 

PROCEDURE ScreenToLayer;

PROCEDURE Execute(h:HANDLE);

	BEGIN
		
		SetObjectVariableBoolean(h,1160,TRUE);
	END;

BEGIN
	SetPref(6839,TRUE);
	ForEachObject(Execute,ALL);
END;

Run(ScreenToLayer);

 

Please note that in this case, you will need to engage the legacy 2D features with SetPref(6839,TRUE) to enable the screen plane before you can assign objects to it.

Edited by Jesse Cogswell
  • Like 1
Link to comment

I think the layer to screen is working well this way

 

PROCEDURE LayerToScreen;

PROCEDURE Execute(h:HANDLE);

	BEGIN
		SetObjectVariableBoolean(h,1160,TRUE);
	END;

BEGIN
	SetPref(6839,TRUE);
	ForEachObject(Execute,(PLA='Layer Plane'));
END;

Run(LayerToScreen);

 

Edited by lcda
Link to comment

I'm not sure which version of Vectorworks you are using, but I would add the SetPref(6839,TRUE) call before the ForEachObject call.  If you are running version 2022 or newer, the screen plane is disabled by default, so running your script to force objects onto the screen plane will technically work, but if the Legacy 2D Features option isn't enabled for the drawing, the Plane field in the OIP will be blank.  This command will enable the feature before placing objects on the screen plane.

 

If you are on an older version of VW, please disregard this message but keep it in mind in case you upgrade.

 

Screenshot without SetPref code with Legacy 2D Features disabled at runtime:

image.thumb.png.ce1706cede70d8d78fa94164f12b3636.png

 

Screenshot with SetPref code with Legacy 2D Features disabled at runtime:

image.thumb.png.a6bc8cf7ad8f9c8e9d36462ec5bf4e43.png

  • Like 1
Link to comment

As for the texture By Class, it's a wee bit trickier.  Objects can have multiple components, such as an Extrude's top, sides, and bottom, or a Wall's top, left side, right side, cap, hole, etc.  These are known as "Texture Parts."  There's not really a script command to pull an object's texture parts, so doing a full reset to By Class is kind of tricky.  Texture Part 3 is considered an object's "overall" texture, so the code below will force all objects' Overall part to be by class.

 

PROCEDURE TextureByClass;

PROCEDURE Execute(h:HANDLE);

	BEGIN
		SetTextureRefN(h,-1,3,0);
		ResetObject(h);
	END;
	
BEGIN
	ForEachObject(Execute,INSYMBOL & (ALL));
END;

Run(TextureByClass);

 

However, what you'll discover is that the above script will technically work, with the texture properly updating in the Render tab of the OIP, but the object won't reflect the change until you change a value on one of the object's properties to force the object to reset.  I tried this with extrudes, sweeps, and 3D polygons and all of them exhibited this issue.  I found a solution by creating an array of handles to texturable objects, then running code to set the texture, then duplicate the object, and delete the original.  It's complicated, but I think it works.

 

PROCEDURE TextureByClass;

VAR

	objectArray:DYNARRAY[] OF HANDLE;
	numObjects:INTEGER;

PROCEDURE SetTextureByClass(arr:DYNARRAY[] OF HANDLE; num:INTEGER);

	VAR

		i:INTEGER;
		hParent,hDup:HANDLE;
		sName:STRING;
	
	BEGIN
		FOR i:=1 TO num DO
			BEGIN
				sName:=GetName(arr[i]);
				hParent:=GetParent(arr[i]);
				
				SetTextureRefN(arr[i],-1,3,0);
				ResetObject(arr[i]);
				
				hDup:=CreateDuplicateObject(arr[i],hParent);
				DelObject(arr[i]);
				SetName(hDup,sName);
			END;
	END;

PROCEDURE BuildArray(h:HANDLE);

	BEGIN
		IF(GetObjectVariableBoolean(h,500)) THEN
			BEGIN
				numObjects:=numObjects+1;
				ALLOCATE objectArray[1..numObjects];
				objectArray[numObjects]:=h;
			END;
	END;
	
BEGIN
	ForEachObject(BuildArray,INSYMBOL & (ALL));
	SetTextureByClass(objectArray,numObjects);
END;

Run(TextureByClass);

 

  • Like 2
Link to comment
On 12/28/2022 at 5:14 PM, Jesse Cogswell said:

the object won't reflect the change until you change a value on one of the object's properties to force the object to reset

I know with Wall issues you can often fix things by moving the wall 0,0.  Maybe this would work, too.

Link to comment

That was the first thing I tried.  But the only way the texture would reset was if a parameter in the OIP was changed or if the object was moved to a different layer.  Moving the object to a different layer and back worked, but only in drawings with more than one layer, and it didn't work with objects inside symbols.  The duplication turned out to be the easiest solution in this case.

Link to comment

Here you go.  This script will open up a dialog window so you can select the target class.

 

PROCEDURE ChangeTextClass;

VAR

	targetClass:STRING;
	dialog,layoutDialog:LONGINT;
	check:BOOLEAN;

PROCEDURE Execute(h:HANDLE);

{Changes class of given object to targetClass}

	BEGIN
		SetClass(h,targetClass);
		ResetObject(h);
	END;

FUNCTION DrawDialog(DName:STRING) : LONGINT;

{Creates dialog box and returns dialog ID}

	CONST
	
		kClassWidth = 25;

	VAR
	
		dia:LONGINT;
	
	BEGIN
		dia:=CreateLayout(DName,FALSE,'OK','Cancel');
		
		CreateStaticText(dia,11,'Select Target Class',-1);
		CreateClassPullDownMenu(dia,21,kClassWidth);
		
		SetFirstLayoutItem(dia,11);
		SetRightItem(dia,11,21,0,0);
		
		DrawDialog:=dia;
	END;

PROCEDURE DialogHandler(VAR item,data:LONGINT);

{Handles dialog box}

	VAR
	
		int:INTEGER;

	BEGIN
		CASE item OF
			SetupDialogC:
				BEGIN
				END;
			1: {OK}
				BEGIN
					GetSelectedChoiceInfo(dialog,21,0,int,targetClass);

					check:=TRUE;
				END;
			2: {Cancel}
				BEGIN
					check:=FALSE;
				END;
		END;
	END;

BEGIN
	dialog:=DrawDialog('Select Text Class');
	layoutDialog:=RunLayoutDialog(dialog,DialogHandler);
	
	IF(check) THEN ForEachObject(Execute,INSYMBOL & INOBJECT & INVIEWPORT & (T=TEXT));
	
	ReDrawAll;
END;

Run(ChangeTextClass);

 

Slight word of warning: This script will change the text within Plug-in Objects as well.  With most PIOs, the text objects inherit the class of the PIO itself, so if anything causes the PIO to be reset (layer changed, OIP value changed, moved or rotated with certain PIOs, etc), the text class will be reset to the PIO class.  But the script above WILL work until the object is reset.  There is no way to permanently change the text class for PIOs without editing their code directly, which no script can (or should) do.

Link to comment

Thanks a lot!!!

I have been testing this script and works perfectly but the only problem is that changes things in viewports so I deleted the viewports option but it still does, is there a way this to operate only in design layers

 

Procedure UseClassAttribs;

Procedure Execute(Hd1:Handle);
	BEGIN

	SetFillColorByClass(Hd1);
	SetPenColorByClass(Hd1);
	SetFPatByClass(Hd1);
	SetLWByClass(Hd1);
	SetLSByClass(Hd1);
	SetOpacityByClass(Hd1);
	
	End;
	
BEGIN
	ForEachObject(Execute, (INOBJECT & (ALL)));
End;

Run(UseClassAttribs);



 

Link to comment

The INVIEWPORT flag only affects objects that are in a viewport's annotation or crop space.  Looking at the code above and doing a quick test with it, it is working as intended.  The viewport is only relaying the visual information from Design Layer space, so if objects on Design Layers are now set to By Class, those changes will be reflected in the viewports as well.  You could lock in class overrides per viewport to combat this, but that would be a tricky thing to script out.

 

If you don't want your code to be reflected on Sheet Layers, there is a fix I can recommend.  What you sill want to do is poll whether an object is on a layer using a combination of GetParent and GetTypeNGetParent will return a handle to an object's parent, which could be a symbol, group, PIO, layer, or viewport.  GetTypeN will return a number based on the type of object passed to it.  In this case, we're looking for 31, which is the internal object number of a layer.  From there, we can use GetObjectVariableInt on the handle to the layer and selector 154 to poll whether the layer is a Design Layer (return 1), or a Sheet Layer (return 2).  If it returns a 1, we execute the code.  The finished code would look something like this:

Procedure UseClassAttribs;

Procedure Execute(Hd1:Handle);

	CONST
	
		kDesignLayer = 1;
		kLayer = 31;
		kLayerType = 154;
	
	VAR
	
		hParent:HANDLE;
		
	BEGIN
		hParent:=GetParent(Hd1);
		IF(GetTypeN(hParent)=kLayer) THEN
			BEGIN
				IF(GetObjectVariableInt(hParent,kLayerType)=kDesignLayer) THEN
					BEGIN
						SetFillColorByClass(Hd1);
						SetPenColorByClass(Hd1);
						SetFPatByClass(Hd1);
						SetLWByClass(Hd1);
						SetLSByClass(Hd1);
						SetOpacityByClass(Hd1);
					END;
			END;
	End;
	
BEGIN
	ForEachObject(Execute, (INOBJECT & (ALL)));
End;

Run(UseClassAttribs);

 

  • Like 1
Link to comment

Or maybe we can make an option to select the layers you want to change as you do on text option

this script is not working well it only changes the objects on actual layer, how can I do to change all objects??

 

PROCEDURE ScreenToLayer;

PROCEDURE Execute(h:HANDLE);

	BEGIN
		SetObjectVariableBoolean(h,1160,FALSE);
	END;

BEGIN
	ForEachObject(Execute,(PLA='Screen Plane'));
END;

Run(ScreenToLayer);

 

Edited by lcda
Link to comment

Ok I think the correct way for these 2 scripts are this:

Layer to screen

 

PROCEDURE LayerToScreen;

PROCEDURE Execute(h:HANDLE);

	BEGIN
		SetObjectVariableBoolean(h,1160,TRUE);
	END;

BEGIN
	SetPref(6839,TRUE);
	ForEachObject(Execute,ALL);
END;

Run(LayerToScreen);


Screen to layer

 

PROCEDURE ScreenToLayer;

PROCEDURE Execute(h:HANDLE);

	BEGIN
		SetObjectVariableBoolean(h,1160,FALSE);
	END;

BEGIN

	ForEachObject(Execute, (PLA='Screen Plane') & (ALL));

END;

Run(ScreenToLayer);

 

Link to comment
  • 4 months later...
On 12/31/2022 at 11:53 AM, Jesse Cogswell said:

Here you go.  This script will open up a dialog window so you can select the target class.

 

Thanks, I added a criteria dialog to your script so the selection criteria is defined by the script prior to selecting the target class.

 

PROCEDURE ChangeTextClass;

VAR

	CriteriaInput,targetClass:STRING;
	Pass,dialog,layoutDialog:LONGINT;
	check:BOOLEAN;

PROCEDURE Execute(h:HANDLE);

{Changes class of given object to targetClass}

	BEGIN
		SetClass(h,targetClass);
		ResetObject(h);
	END;

FUNCTION DrawDialog(DName:STRING) : LONGINT;

{Creates dialog box and returns dialog ID}

	CONST
	
		kClassWidth = 25;

	VAR
	
		dia:LONGINT;
	
	BEGIN
		dia:=CreateLayout(DName,FALSE,'OK','Cancel');
		
		CreateStaticText(dia,11,'Select Target Class',-1);
		CreateClassPullDownMenu(dia,21,kClassWidth);
		
		SetFirstLayoutItem(dia,11);
		SetRightItem(dia,11,21,0,0);
		
		DrawDialog:=dia;
	END;

PROCEDURE DialogHandler(VAR item,data:LONGINT);

{Handles dialog box}

	VAR
	
		int:INTEGER;

	BEGIN
		CASE item OF
			SetupDialogC:
				BEGIN
				END;
			1: {OK}
				BEGIN
					GetSelectedChoiceInfo(dialog,21,0,int,targetClass);

					check:=TRUE;
				END;
			2: {Cancel}
				BEGIN
					check:=FALSE;
				END;
		END;
	END;

BEGIN
	Pass:=EditCriteriaWithUI(CriteriaInput);
	dialog:=DrawDialog('Select Text Class');
	layoutDialog:=RunLayoutDialog(dialog,DialogHandler);
	
	IF(check) THEN ForEachObject(Execute,CriteriaInput);
	
	ReDrawAll;
END;

Run(ChangeTextClass);

 

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