lcda Posted December 28, 2022 Share Posted December 28, 2022 Is there a way to convert all objects in file or all objects In drawing to screen on layer plane or assign all color an line class attributes or rendering by class? Quote Link to comment
Pat Stanford Posted December 28, 2022 Share Posted December 28, 2022 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 Quote Link to comment
lcda Posted December 28, 2022 Author Share Posted December 28, 2022 {/////////////////////////////////////////// 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 Quote Link to comment
Pat Stanford Posted December 28, 2022 Share Posted December 28, 2022 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. Quote Link to comment
lcda Posted December 28, 2022 Author Share Posted December 28, 2022 yes I mean exactly that change all objects to class render texture and want to change all objects in document to his class attributes, actual script just works for selected objects. Quote Link to comment
lcda Posted December 28, 2022 Author Share Posted December 28, 2022 (edited) 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 December 28, 2022 by lcda Quote Link to comment
Jesse Cogswell Posted December 28, 2022 Share Posted December 28, 2022 (edited) 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 December 28, 2022 by Jesse Cogswell 1 Quote Link to comment
lcda Posted December 28, 2022 Author Share Posted December 28, 2022 (edited) Thanks a lot both for the inverse option I have to change this string? ForEachObject(Execute,(PLA='Screen Plane')); Edited December 28, 2022 by lcda Quote Link to comment
lcda Posted December 28, 2022 Author Share Posted December 28, 2022 (edited) 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 December 28, 2022 by lcda Quote Link to comment
Jesse Cogswell Posted December 28, 2022 Share Posted December 28, 2022 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: Screenshot with SetPref code with Legacy 2D Features disabled at runtime: 1 Quote Link to comment
lcda Posted December 28, 2022 Author Share Posted December 28, 2022 Ok im using 2021 but you are right 2022 has no screen plane so I´m going to add that line Quote Link to comment
Jesse Cogswell Posted December 29, 2022 Share Posted December 29, 2022 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); 2 Quote Link to comment
lcda Posted December 30, 2022 Author Share Posted December 30, 2022 (edited) Wooo you ara so clever this is awesome!! Thanks a lot!! Edited December 30, 2022 by lcda Quote Link to comment
E|FA Posted December 30, 2022 Share Posted December 30, 2022 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. Quote Link to comment
Jesse Cogswell Posted December 30, 2022 Share Posted December 30, 2022 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. Quote Link to comment
lcda Posted December 31, 2022 Author Share Posted December 31, 2022 (edited) 1 More please, how could I change change all TEXT in file to a specific class?? Edited December 31, 2022 by lcda Quote Link to comment
Jesse Cogswell Posted December 31, 2022 Share Posted December 31, 2022 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. Quote Link to comment
lcda Posted December 31, 2022 Author Share Posted December 31, 2022 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); Quote Link to comment
Jesse Cogswell Posted December 31, 2022 Share Posted December 31, 2022 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 GetTypeN. GetParent 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); 1 Quote Link to comment
lcda Posted January 1, 2023 Author Share Posted January 1, 2023 (edited) 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 January 1, 2023 by lcda Quote Link to comment
lcda Posted January 1, 2023 Author Share Posted January 1, 2023 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); Quote Link to comment
The Hamma Posted May 5, 2023 Share Posted May 5, 2023 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); Quote Link to comment
Recommended Posts
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.