Neda Roohnia Posted April 28, 2023 Share Posted April 28, 2023 Hi everyone, I am trying to come up with a Python script that identifies the largest viewport on a sheetlayer, gets its scale, and updates the title block scale field for each sheetlayer. I have put together a very preliminary code for this. import vs Handle = vs.GetObject('THISISIT') strNR1 = vs.GetObjectVariableReal(Handle, 1003) #Sheet data record format and field strRecordName = 'Title Block Sheet Data' strRecordField = 'Scale' def SetRecord(h): vs.SetRField(h,strRecordName,strRecordField,strNR1); vs.ResetObject(h); criteria = '((R in [' + "'" + strRecordName + "'" + ']))'; vs.ForEachObject( SetRecord, criteria); This code works as long as I know the viewport's name (in this example: "THISISIT"), also it puts the same scale on all the sheetlayers' titleblocks. Any inputs will be much appreciated! Quote Link to comment
twk Posted April 28, 2023 Share Posted April 28, 2023 (edited) I’d actually loop through viewports via sheets: 1. Generate a list of sheet layers. 2. For each sheet layer in the list, use a criteria that searches for viewports with T=Viewport only on this layer. 3. To find a title block within the same loop, use another criteria that searches for a plugin name of "Title Block Border" on the same layer. 4. Within the loop of step 2, locate the largest viewport. You can choose to use the viewport with the largest scale or the one with the largest bounding box. Once found, write the scale to the handle of the title block found in step 3. When I have time to code, I'll see if I can post something Also try to always use f-strings for concatenation. eg criteria = f"((R in ['{strRecordName}']))" Edited April 28, 2023 by twk 1 Quote Link to comment
twk Posted April 28, 2023 Share Posted April 28, 2023 And here is what I came up with, (FYI, I used chatGPT to explain the code with inline comments!). ** As always, save before running the script, and no responsibility taken for loss of work 😅 ** import vs # Define a function to list the names of all sheet layers in the current document def list_sheet_layer_names(): layer_names = [] hLayer = vs.FLayer() # Use a while loop and the NextLayer() function to iterate through all the sheet layers in the document while hLayer != None: layer_names.append(hLayer) hLayer = vs.NextLayer(hLayer) # Use a lambda function to filter the list of layer names to only include sheet layers layer_type = lambda x:vs.GetObjectVariableInt(x, 154) layer_names = [vs.GetLName(x) for x in layer_names if layer_type(x) == 2] return layer_names # Define a function to get the handles of all objects in the current document that meet certain criteria def get_objects_from_criteria(criteria): object_handles = [] def get_obj(h): object_handles.append(h) # Use the ForEachObject() function to iterate through all objects in the document and add their handles to the list if they meet the criteria vs.ForEachObject(get_obj, criteria) return object_handles # Define a function to calculate the area of a given object def get_object_area(object): top_left, bot_right = vs.GetBBox(object) length = bot_right[0] - top_left[0] height = top_left[1] - bot_right[1] return length * height # Iterate through all sheet layers in the current document for layer in list_sheet_layer_names(): # Define criteria strings to find title blocks and viewports on the current layer titleblock_crit_str = f"(((L='{layer}') & (PON='Title Block Border')))" viewports_crit = f"(((L='{layer}') & (T=VIEWPORT)))" # Use the get_objects_from_criteria() function to get lists of title blocks and viewports on the current layer titleblocks = get_objects_from_criteria(titleblock_crit_str) viewports = get_objects_from_criteria(viewports_crit) # If there is at least one title block and one viewport on the current layer, find the largest viewport and set the scale of the title block to match if all([len(titleblocks)>0, len(viewports)>0]): titleblock = titleblocks[0] # get single first found only vp_area_max = 0.0 vp_largest = None # Iterate through all viewports on the current layer and find the one with the largest area for viewport in viewports: vp_area = get_object_area(viewport) if vp_area > vp_area_max: vp_area_max = vp_area vp_largest = viewport # If a largest viewport is found, set the scale of the title block to match if vp_largest: vp_scale = vs.GetObjectVariableReal(vp_largest, 1003) vs.SetRField(titleblock, 'Title Block Sheet Data', 'Scale', f'1:{vp_scale:.0f}') Quote Link to comment
Neda Roohnia Posted April 28, 2023 Author Share Posted April 28, 2023 14 minutes ago, twk said: And here is what I came up with, (FYI, I used chatGPT to explain the code with inline comments!). ** As always, save before running the script, and no responsibility taken for loss of work 😅 ** Thanks soo much, I really appreciate your very quick response and help! I will let you know in case of any issues! Ah yea, ChatGPT is awesome for that, it confused me tho to generate this code!! 😄 import vs # Define a function to list the names of all sheet layers in the current document def list_sheet_layer_names(): layer_names = [] hLayer = vs.FLayer() # Use a while loop and the NextLayer() function to iterate through all the sheet layers in the document while hLayer != None: layer_names.append(hLayer) hLayer = vs.NextLayer(hLayer) # Use a lambda function to filter the list of layer names to only include sheet layers layer_type = lambda x:vs.GetObjectVariableInt(x, 154) layer_names = [vs.GetLName(x) for x in layer_names if layer_type(x) == 2] return layer_names # Define a function to get the handles of all objects in the current document that meet certain criteria def get_objects_from_criteria(criteria): object_handles = [] def get_obj(h): object_handles.append(h) # Use the ForEachObject() function to iterate through all objects in the document and add their handles to the list if they meet the criteria vs.ForEachObject(get_obj, criteria) return object_handles # Define a function to calculate the area of a given object def get_object_area(object): top_left, bot_right = vs.GetBBox(object) length = bot_right[0] - top_left[0] height = top_left[1] - bot_right[1] return length * height # Iterate through all sheet layers in the current document for layer in list_sheet_layer_names(): # Define criteria strings to find title blocks and viewports on the current layer titleblock_crit_str = f"(((L='{layer}') & (PON='Title Block Border')))" viewports_crit = f"(((L='{layer}') & (T=VIEWPORT)))" # Use the get_objects_from_criteria() function to get lists of title blocks and viewports on the current layer titleblocks = get_objects_from_criteria(titleblock_crit_str) viewports = get_objects_from_criteria(viewports_crit) # If there is at least one title block and one viewport on the current layer, find the largest viewport and set the scale of the title block to match if all([len(titleblocks)>0, len(viewports)>0]): titleblock = titleblocks[0] # get single first found only vp_area_max = 0.0 vp_largest = None # Iterate through all viewports on the current layer and find the one with the largest area for viewport in viewports: vp_area = get_object_area(viewport) if vp_area > vp_area_max: vp_area_max = vp_area vp_largest = viewport # If a largest viewport is found, set the scale of the title block to match if vp_largest: vp_scale = vs.GetObjectVariableReal(vp_largest, 1003) vs.SetRField(titleblock, 'Title Block Sheet Data', 'Scale', f'1:{vp_scale:.0f}') Quote Link to comment
Neda Roohnia Posted May 1, 2023 Author Share Posted May 1, 2023 On 4/28/2023 at 8:27 AM, twk said: And here is what I came up with, (FYI, I used chatGPT to explain the code with inline comments!). ** As always, save before running the script, and no responsibility taken for loss of work 😅 ** import vs # Define a function to list the names of all sheet layers in the current document def list_sheet_layer_names(): layer_names = [] hLayer = vs.FLayer() # Use a while loop and the NextLayer() function to iterate through all the sheet layers in the document while hLayer != None: layer_names.append(hLayer) hLayer = vs.NextLayer(hLayer) # Use a lambda function to filter the list of layer names to only include sheet layers layer_type = lambda x:vs.GetObjectVariableInt(x, 154) layer_names = [vs.GetLName(x) for x in layer_names if layer_type(x) == 2] return layer_names # Define a function to get the handles of all objects in the current document that meet certain criteria def get_objects_from_criteria(criteria): object_handles = [] def get_obj(h): object_handles.append(h) # Use the ForEachObject() function to iterate through all objects in the document and add their handles to the list if they meet the criteria vs.ForEachObject(get_obj, criteria) return object_handles # Define a function to calculate the area of a given object def get_object_area(object): top_left, bot_right = vs.GetBBox(object) length = bot_right[0] - top_left[0] height = top_left[1] - bot_right[1] return length * height # Iterate through all sheet layers in the current document for layer in list_sheet_layer_names(): # Define criteria strings to find title blocks and viewports on the current layer titleblock_crit_str = f"(((L='{layer}') & (PON='Title Block Border')))" viewports_crit = f"(((L='{layer}') & (T=VIEWPORT)))" # Use the get_objects_from_criteria() function to get lists of title blocks and viewports on the current layer titleblocks = get_objects_from_criteria(titleblock_crit_str) viewports = get_objects_from_criteria(viewports_crit) # If there is at least one title block and one viewport on the current layer, find the largest viewport and set the scale of the title block to match if all([len(titleblocks)>0, len(viewports)>0]): titleblock = titleblocks[0] # get single first found only vp_area_max = 0.0 vp_largest = None # Iterate through all viewports on the current layer and find the one with the largest area for viewport in viewports: vp_area = get_object_area(viewport) if vp_area > vp_area_max: vp_area_max = vp_area vp_largest = viewport # If a largest viewport is found, set the scale of the title block to match if vp_largest: vp_scale = vs.GetObjectVariableReal(vp_largest, 1003) vs.SetRField(titleblock, 'Title Block Sheet Data', 'Scale', f'1:{vp_scale:.0f}') It's very strange! I tried the code, it doesn't give any errors, but it doesn't do anything, either! I was thinking of a couple of things; what if I revise it in a way that it mentions the titleblock's name directly rather than search for the titleblocks? The titleblock symbol's name is defined in our template file. I appreciate if you point out to any possible issue that causes this! Again, really appreciate your input and help!! Quote Link to comment
twk Posted May 1, 2023 Share Posted May 1, 2023 Interesting, "Title Block Border" objects may have a symbol name within it that controls the graphical layout of it, however this symbol is housed in a unique object (the Title Block Border object), that is placed on each sheet layer separately. If you were to go down the naming route, you'd have to have a unique name for each title block border object on each sheet layer, which is not optimal. I've added checks in the code below, to alert you of the amount of sheets found in the document, and then another alert dialog to tell you if the criteria didn't find any title blocks or viewports on the layer, as its looping through it. Try it again and see what messages the alert dialog throws out. If not, post/DM me your VWX file, maybe your sheet/title block setup is different. import vs alert_dialog = lambda x:vs.AlrtDialog(str(x)) def list_sheet_layer_names(): layer_names = [] hLayer = vs.FLayer() while hLayer != None: layer_names.append(hLayer) hLayer = vs.NextLayer(hLayer) layer_type = lambda x: vs.GetObjectVariableInt(x, 154) layer_names = [vs.GetLName(x) for x in layer_names if layer_type(x) == 2] # filter to only include sheet layers return layer_names def get_objects_from_criteria(criteria): object_handles = [] def get_obj(h): object_handles.append(h) vs.ForEachObject(get_obj, criteria) return object_handles def get_object_area(object): top_left, bot_right = vs.GetBBox(object) length = bot_right[0] - top_left[0] height = top_left[1] - bot_right[1] return length * height sheet_layer_names = list_sheet_layer_names() alert_dialog(f"No. Sheets in Document : {len(sheet_layer_names)}") if len(sheet_layer_names) > 0: for layer in list_sheet_layer_names(): titleblock_crit_str = f"(((L='{layer}') & (PON='Title Block Border')))" viewports_crit = f"(((L='{layer}') & (T=VIEWPORT)))" titleblocks = get_objects_from_criteria(titleblock_crit_str) viewports = get_objects_from_criteria(viewports_crit) if all([len(titleblocks) > 0, len(viewports) > 0]): titleblock = titleblocks[0] # get single first found only vp_area_max = 0.0 vp_largest = None for viewport in viewports: vp_area = get_object_area(viewport) if vp_area > vp_area_max: vp_area_max = vp_area vp_largest = viewport if vp_largest: vp_scale = vs.GetObjectVariableReal(vp_largest, 1003) vs.SetRField(titleblock, 'Title Block Sheet Data', 'Scale', f'1:{vp_scale:.0f}') else: alert_dialog(f"No Title Block or Viewport found on sheet {layer}") Quote Link to comment
Neda Roohnia Posted May 3, 2023 Author Share Posted May 3, 2023 On 4/28/2023 at 8:27 AM, twk said: And here is what I came up with, (FYI, I used chatGPT to explain the code with inline comments!). ** As always, save before running the script, and no responsibility taken for loss of work 😅 ** import vs # Define a function to list the names of all sheet layers in the current document def list_sheet_layer_names(): layer_names = [] hLayer = vs.FLayer() # Use a while loop and the NextLayer() function to iterate through all the sheet layers in the document while hLayer != None: layer_names.append(hLayer) hLayer = vs.NextLayer(hLayer) # Use a lambda function to filter the list of layer names to only include sheet layers layer_type = lambda x:vs.GetObjectVariableInt(x, 154) layer_names = [vs.GetLName(x) for x in layer_names if layer_type(x) == 2] return layer_names # Define a function to get the handles of all objects in the current document that meet certain criteria def get_objects_from_criteria(criteria): object_handles = [] def get_obj(h): object_handles.append(h) # Use the ForEachObject() function to iterate through all objects in the document and add their handles to the list if they meet the criteria vs.ForEachObject(get_obj, criteria) return object_handles # Define a function to calculate the area of a given object def get_object_area(object): top_left, bot_right = vs.GetBBox(object) length = bot_right[0] - top_left[0] height = top_left[1] - bot_right[1] return length * height # Iterate through all sheet layers in the current document for layer in list_sheet_layer_names(): # Define criteria strings to find title blocks and viewports on the current layer titleblock_crit_str = f"(((L='{layer}') & (PON='Title Block Border')))" viewports_crit = f"(((L='{layer}') & (T=VIEWPORT)))" # Use the get_objects_from_criteria() function to get lists of title blocks and viewports on the current layer titleblocks = get_objects_from_criteria(titleblock_crit_str) viewports = get_objects_from_criteria(viewports_crit) # If there is at least one title block and one viewport on the current layer, find the largest viewport and set the scale of the title block to match if all([len(titleblocks)>0, len(viewports)>0]): titleblock = titleblocks[0] # get single first found only vp_area_max = 0.0 vp_largest = None # Iterate through all viewports on the current layer and find the one with the largest area for viewport in viewports: vp_area = get_object_area(viewport) if vp_area > vp_area_max: vp_area_max = vp_area vp_largest = viewport # If a largest viewport is found, set the scale of the title block to match if vp_largest: vp_scale = vs.GetObjectVariableReal(vp_largest, 1003) vs.SetRField(titleblock, 'Title Block Sheet Data', 'Scale', f'1:{vp_scale:.0f}') Hi there, thanks a lot for sending the two versions of your script! I just realized that they both work actually, the only thing is that I have to "update" the titleblock for the scale to update by checking and un-checking "Activate Title Block" on the object info panel. I was wondering if there is a way to include this "updating" into the script somehow. My other question is that how should I change the script to show the imperial scales properly.. i.e. 1/8" = 1'0" instead of 1:96. Many thanks! Quote Link to comment
Neda Roohnia Posted May 3, 2023 Author Share Posted May 3, 2023 13 minutes ago, Neda Roohnia said: Hi there, thanks a lot for sending the two versions of your script! I just realized that they both work actually, the only thing is that I have to "update" the titleblock for the scale to update by checking and un-checking "Activate Title Block" on the object info panel. I was wondering if there is a way to include this "updating" into the script somehow. My other question is that how should I change the script to show the imperial scales properly.. i.e. 1/8" = 1'0" instead of 1:96. Many thanks! On 4/28/2023 at 8:27 AM, twk said: And here is what I came up with, (FYI, I used chatGPT to explain the code with inline comments!). ** As always, save before running the script, and no responsibility taken for loss of work 😅 ** import vs # Define a function to list the names of all sheet layers in the current document def list_sheet_layer_names(): layer_names = [] hLayer = vs.FLayer() # Use a while loop and the NextLayer() function to iterate through all the sheet layers in the document while hLayer != None: layer_names.append(hLayer) hLayer = vs.NextLayer(hLayer) # Use a lambda function to filter the list of layer names to only include sheet layers layer_type = lambda x:vs.GetObjectVariableInt(x, 154) layer_names = [vs.GetLName(x) for x in layer_names if layer_type(x) == 2] return layer_names # Define a function to get the handles of all objects in the current document that meet certain criteria def get_objects_from_criteria(criteria): object_handles = [] def get_obj(h): object_handles.append(h) # Use the ForEachObject() function to iterate through all objects in the document and add their handles to the list if they meet the criteria vs.ForEachObject(get_obj, criteria) return object_handles # Define a function to calculate the area of a given object def get_object_area(object): top_left, bot_right = vs.GetBBox(object) length = bot_right[0] - top_left[0] height = top_left[1] - bot_right[1] return length * height # Iterate through all sheet layers in the current document for layer in list_sheet_layer_names(): # Define criteria strings to find title blocks and viewports on the current layer titleblock_crit_str = f"(((L='{layer}') & (PON='Title Block Border')))" viewports_crit = f"(((L='{layer}') & (T=VIEWPORT)))" # Use the get_objects_from_criteria() function to get lists of title blocks and viewports on the current layer titleblocks = get_objects_from_criteria(titleblock_crit_str) viewports = get_objects_from_criteria(viewports_crit) # If there is at least one title block and one viewport on the current layer, find the largest viewport and set the scale of the title block to match if all([len(titleblocks)>0, len(viewports)>0]): titleblock = titleblocks[0] # get single first found only vp_area_max = 0.0 vp_largest = None # Iterate through all viewports on the current layer and find the one with the largest area for viewport in viewports: vp_area = get_object_area(viewport) if vp_area > vp_area_max: vp_area_max = vp_area vp_largest = viewport # If a largest viewport is found, set the scale of the title block to match if vp_largest: vp_scale = vs.GetObjectVariableReal(vp_largest, 1003) vs.SetRField(titleblock, 'Title Block Sheet Data', 'Scale', f'1:{vp_scale:.0f}') Oh I figured a partial answer to one of my questions; I need to go to Tools...> Utilities...> Reset All Plug-ins and then it works! Quote Link to comment
Pat Stanford Posted May 3, 2023 Share Posted May 3, 2023 You should be able to add vs.ResetObject(titleblock) at the end (or if you are processing multiple title blocks, at the end of the block doing the processing) and have each one reset individually instead of resetting everything in the drawing. 1 Quote Link to comment
Neda Roohnia Posted May 3, 2023 Author Share Posted May 3, 2023 11 minutes ago, Pat Stanford said: You should be able to add vs.ResetObject(titleblock) at the end (or if you are processing multiple title blocks, at the end of the block doing the processing) and have each one reset individually instead of resetting everything in the drawing. Hi Pat, I just added that in and it works like a magic! Thanks a lot! Now I am trying to add some "if" loops for converting the engineering scales to Architectural...I will keep you posted on how it goes! 1 Quote Link to comment
twk Posted May 4, 2023 Share Posted May 4, 2023 6 hours ago, Neda Roohnia said: My other question is that how should I change the script to show the imperial scales properly.. i.e. 1/8" = 1'0" instead of 1:96. Many thanks! I'll have to think about this, the vs.GetObjectVariableReal(vp_largest, 1003) function returns the scale in mm, regardless of the document units. I don't have any experience either in imperial scales as we use the metric system. Will post back when found a solution.. 1 Quote Link to comment
MullinRJ Posted May 4, 2023 Share Posted May 4, 2023 If a function doesn't exist, you can always create a lookup function for the typical values you find in Imperial Scales. Something like this: def ImpScale(SF): # return the imperial scale string for typical Layer Scale Factor values (SF) if SF == 4: return '3"' elif SF == 6: return '2"' elif SF == 8: return '1-1/2"' elif SF == 12: return '1"' elif SF == 16: return '3/4"' elif SF == 24: return '1/2"' elif SF == 32: return '3/8"' elif SF == 48: return '1/4"' elif SF == 64: return '3/16"' elif SF == 96: return '1/8"' elif SF == 192: return '1/16"' elif SF == 384: return '1/32"' elif SF == 120: return '1"='+"10'" elif SF == 240: return '1"='+"20'" elif SF == 360: return '1"='+"30'" elif SF == 480: return '1"='+"40'" elif SF == 600: return '1"='+"50'" elif SF == 1200: return '1"='+"100'" else: return '1:'+str(SF) SF = 1 while not vs.DidCancel(): SF = vs.IntDialog( 'Enter a scale factor', str(SF)) if not vs.DidCancel(): vs.AlrtDialog(ImpScale(SF)) # test the function Raymond 3 Quote Link to comment
Neda Roohnia Posted May 4, 2023 Author Share Posted May 4, 2023 On 4/28/2023 at 8:27 AM, twk said: And here is what I came up with, (FYI, I used chatGPT to explain the code with inline comments!). ** As always, save before running the script, and no responsibility taken for loss of work 😅 ** import vs # Define a function to list the names of all sheet layers in the current document def list_sheet_layer_names(): layer_names = [] hLayer = vs.FLayer() # Use a while loop and the NextLayer() function to iterate through all the sheet layers in the document while hLayer != None: layer_names.append(hLayer) hLayer = vs.NextLayer(hLayer) # Use a lambda function to filter the list of layer names to only include sheet layers layer_type = lambda x:vs.GetObjectVariableInt(x, 154) layer_names = [vs.GetLName(x) for x in layer_names if layer_type(x) == 2] return layer_names # Define a function to get the handles of all objects in the current document that meet certain criteria def get_objects_from_criteria(criteria): object_handles = [] def get_obj(h): object_handles.append(h) # Use the ForEachObject() function to iterate through all objects in the document and add their handles to the list if they meet the criteria vs.ForEachObject(get_obj, criteria) return object_handles # Define a function to calculate the area of a given object def get_object_area(object): top_left, bot_right = vs.GetBBox(object) length = bot_right[0] - top_left[0] height = top_left[1] - bot_right[1] return length * height # Iterate through all sheet layers in the current document for layer in list_sheet_layer_names(): # Define criteria strings to find title blocks and viewports on the current layer titleblock_crit_str = f"(((L='{layer}') & (PON='Title Block Border')))" viewports_crit = f"(((L='{layer}') & (T=VIEWPORT)))" # Use the get_objects_from_criteria() function to get lists of title blocks and viewports on the current layer titleblocks = get_objects_from_criteria(titleblock_crit_str) viewports = get_objects_from_criteria(viewports_crit) # If there is at least one title block and one viewport on the current layer, find the largest viewport and set the scale of the title block to match if all([len(titleblocks)>0, len(viewports)>0]): titleblock = titleblocks[0] # get single first found only vp_area_max = 0.0 vp_largest = None # Iterate through all viewports on the current layer and find the one with the largest area for viewport in viewports: vp_area = get_object_area(viewport) if vp_area > vp_area_max: vp_area_max = vp_area vp_largest = viewport # If a largest viewport is found, set the scale of the title block to match if vp_largest: vp_scale = vs.GetObjectVariableReal(vp_largest, 1003) vs.SetRField(titleblock, 'Title Block Sheet Data', 'Scale', f'1:{vp_scale:.0f}') 11 hours ago, MullinRJ said: If a function doesn't exist, you can always create a lookup function for the typical values you find in Imperial Scales. Something like this: def ImpScale(SF): # return the imperial scale string for typical Layer Scale Factor values (SF) if SF == 4: return '3"' elif SF == 6: return '2"' elif SF == 8: return '1-1/2"' elif SF == 12: return '1"' elif SF == 16: return '3/4"' elif SF == 24: return '1/2"' elif SF == 32: return '3/8"' elif SF == 48: return '1/4"' elif SF == 64: return '3/16"' elif SF == 96: return '1/8"' elif SF == 192: return '1/16"' elif SF == 384: return '1/32"' elif SF == 120: return '1"='+"10'" elif SF == 240: return '1"='+"20'" elif SF == 360: return '1"='+"30'" elif SF == 480: return '1"='+"40'" elif SF == 600: return '1"='+"50'" elif SF == 1200: return '1"='+"100'" else: return '1:'+str(SF) SF = 1 while not vs.DidCancel(): SF = vs.IntDialog( 'Enter a scale factor', str(SF)) if not vs.DidCancel(): vs.AlrtDialog(ImpScale(SF)) # test the function Raymond This is very helpful! Thank you so much! Quote Link to comment
Neda Roohnia Posted May 4, 2023 Author Share Posted May 4, 2023 I revised the code to account for the imperial scales as below: import vs # Define a function to list the names of all sheet layers in the current document def list_sheet_layer_names(): layer_names = [] hLayer = vs.FLayer() # Use a while loop and the NextLayer() function to iterate through all the sheet layers in the document while hLayer != None: layer_names.append(hLayer) hLayer = vs.NextLayer(hLayer) # Use a lambda function to filter the list of layer names to only include sheet layers layer_type = lambda x:vs.GetObjectVariableInt(x, 154) layer_names = [vs.GetLName(x) for x in layer_names if layer_type(x) == 2] return layer_names # Define a function to get the handles of all objects in the current document that meet certain criteria def get_objects_from_criteria(criteria): object_handles = [] def get_obj(h): object_handles.append(h) # Use the ForEachObject() function to iterate through all objects in the document and add their handles to the list if they meet the criteria vs.ForEachObject(get_obj, criteria) return object_handles # Define a function to calculate the area of a given object def get_object_area(object): top_left, bot_right = vs.GetBBox(object) length = bot_right[0] - top_left[0] height = top_left[1] - bot_right[1] return length * height def ImpScale(SF): if SF == 48: return "1/4\"=1'0\"" elif SF == 64: return "3/16\"=1'0\"" elif SF == 96: return "1/8\"=1'0\"" elif SF == 128: return "3/32\"=1'0\"" elif SF == 192: return "1/16\"=1'0\"" elif SF == 384: return "1/32\"=1'0\"" else: return f'1:{SF:.0f}' # Iterate through all sheet layers in the current document for layer in list_sheet_layer_names(): # Define criteria strings to find title blocks and viewports on the current layer titleblock_crit_str = f"(((L='{layer}') & (PON='Title Block Border')))" viewports_crit = f"(((L='{layer}') & (T=VIEWPORT)))" # Use the get_objects_from_criteria() function to get lists of title blocks and viewports on the current layer titleblocks = get_objects_from_criteria(titleblock_crit_str) viewports = get_objects_from_criteria(viewports_crit) # If there is at least one title block and one viewport on the current layer, find the largest viewport and set the scale of the title block to match if all([len(titleblocks)>0, len(viewports)>0]): titleblock = titleblocks[0] # get single first found only vp_area_max = 0.0 vp_largest = None # Iterate through all viewports on the current layer and find the one with the largest area for viewport in viewports: vp_area = get_object_area(viewport) if vp_area > vp_area_max: vp_area_max = vp_area vp_largest = viewport # If a largest viewport is found, set the scale of the title block to match if vp_largest: SF = vs.GetObjectVariableReal(vp_largest, 1003) vs.SetRField(titleblock, 'Title Block Sheet Data', 'Scale', ImpScale(SF)) vs.ResetObject(titleblock) Again, thanks a lot all for helping me on this! 2 Quote Link to comment
Neda Roohnia Posted May 31, 2023 Author Share Posted May 31, 2023 One more question on this code; how can I exclude a specific sheet layer on this code? What if we don't want certain sheets to get updated? Any hints will be much appreciated! Quote Link to comment
Pat Stanford Posted May 31, 2023 Share Posted May 31, 2023 # Use a while loop and the NextLayer() function to iterate through all the sheet layers in the document while hLayer != None: layer_names.append(hLayer) hLayer = vs.NextLayer(hLayer) If there is just a single layer then check the layer name and don't do the append if it is that layer. If it is multiple layers, make a list of those layer names and compare the layer name to the list and don't do the append if they are on the exclude list. If there is some other criteria that you want to exclude them for, then check that criteria and don't do the append if they match that criteria. Maybe something (completely untested and my Python is very weak) like : # Use a while loop and the NextLayer() function to iterate through all the sheet layers in the document while hLayer != None: if vs.GetLName != "Your Layer Name to Exclude": layer_names.append(hLayer) hLayer = vs.NextLayer(hLayer) 2 Quote Link to comment
Neda Roohnia Posted May 31, 2023 Author Share Posted May 31, 2023 5 minutes ago, Pat Stanford said: # Use a while loop and the NextLayer() function to iterate through all the sheet layers in the document while hLayer != None: layer_names.append(hLayer) hLayer = vs.NextLayer(hLayer) If there is just a single layer then check the layer name and don't do the append if it is that layer. If it is multiple layers, make a list of those layer names and compare the layer name to the list and don't do the append if they are on the exclude list. If there is some other criteria that you want to exclude them for, then check that criteria and don't do the append if they match that criteria. Maybe something (completely untested and my Python is very weak) like : # Use a while loop and the NextLayer() function to iterate through all the sheet layers in the document while hLayer != None: if vs.GetLName != "Your Layer Name to Exclude": layer_names.append(hLayer) hLayer = vs.NextLayer(hLayer) Thanks a lot, Pat! Will test this to see! Much appreciated. Quote Link to comment
twk Posted May 31, 2023 Share Posted May 31, 2023 revised list_sheet_layer_names below, added option to provide a list of layernames you want to only be returned. # Define a function to list the names of all sheet layers in the current document def list_sheet_layer_names(filter_layer_names=None): """ @type filter_layer_names: exclusive layer names list ie, only these layers to be returned """ layer_names = [] hLayer = vs.FLayer() # Use a while loop and the NextLayer() function to iterate through all the sheet layers in the document while hLayer != None: layer_names.append(hLayer) if vs.GetObjectVariableInt(hLayer, 154) == 2: layer_name = vs.GetLName(hLayer) if filter_layer_names: if layer_name in filter_layer_names: layer_names.append(layer_name) else: layer_names.append(layer_name) hLayer = vs.NextLayer(hLayer) return layer_names 2 Quote Link to comment
Neda Roohnia Posted May 31, 2023 Author Share Posted May 31, 2023 25 minutes ago, twk said: revised list_sheet_layer_names below, added option to provide a list of layernames you want to only be returned. # Define a function to list the names of all sheet layers in the current document def list_sheet_layer_names(filter_layer_names=None): """ @type filter_layer_names: exclusive layer names list ie, only these layers to be returned """ layer_names = [] hLayer = vs.FLayer() # Use a while loop and the NextLayer() function to iterate through all the sheet layers in the document while hLayer != None: layer_names.append(hLayer) if vs.GetObjectVariableInt(hLayer, 154) == 2: layer_name = vs.GetLName(hLayer) if filter_layer_names: if layer_name in filter_layer_names: layer_names.append(layer_name) else: layer_names.append(layer_name) hLayer = vs.NextLayer(hLayer) return layer_names Thanks a lot! Really appreciate al your help on this! Quote Link to comment
twk Posted June 1, 2023 Share Posted June 1, 2023 there was a mistake in the indent blocking for the last line of the loop, the hLayer = vs.NextLayer(hLayer) shouldn't be nested in the else portion. Fixed below: # Define a function to list the names of all sheet layers in the current document def list_sheet_layer_names(filter_layer_names=None): """ @type filter_layer_names: exclusive layer names list ie, only these layers to be returned """ layer_names = [] hLayer = vs.FLayer() # Use a while loop and the NextLayer() function to iterate through all the sheet layers in the document while hLayer != None: layer_names.append(hLayer) if vs.GetObjectVariableInt(hLayer, 154) == 2: layer_name = vs.GetLName(hLayer) if filter_layer_names: if layer_name in filter_layer_names: layer_names.append(layer_name) else: layer_names.append(layer_name) hLayer = vs.NextLayer(hLayer) return layer_names 1 Quote Link to comment
Pat Stanford Posted June 1, 2023 Share Posted June 1, 2023 Begin/End & Pascal are your friend. 😉😂 2 1 Quote Link to comment
Neda Roohnia Posted June 1, 2023 Author Share Posted June 1, 2023 (edited) 19 hours ago, twk said: there was a mistake in the indent blocking for the last line of the loop, the hLayer = vs.NextLayer(hLayer) shouldn't be nested in the else portion. Fixed below: # Define a function to list the names of all sheet layers in the current document def list_sheet_layer_names(filter_layer_names=None): """ @type filter_layer_names: exclusive layer names list ie, only these layers to be returned """ layer_names = [] hLayer = vs.FLayer() # Use a while loop and the NextLayer() function to iterate through all the sheet layers in the document while hLayer != None: layer_names.append(hLayer) if vs.GetObjectVariableInt(hLayer, 154) == 2: layer_name = vs.GetLName(hLayer) if filter_layer_names: if layer_name in filter_layer_names: layer_names.append(layer_name) else: layer_names.append(layer_name) hLayer = vs.NextLayer(hLayer) return layer_names Again, thanks a lot for updating this, but I still can not figure out where I should put the specific sheetlayer names that I want to exclude on this code. Edited June 1, 2023 by Neda Roohnia Quote Link to comment
twk Posted June 1, 2023 Share Posted June 1, 2023 You know what, I misunderstood your question. You're wanting an excluded list. We'll revise the 'list_sheet_layer_names' function that accepts a list of sheets to be 'excluded' as a parameter. # Define a function to list the names of all sheet layers in the current document def list_sheet_layer_names(excluded_layer_names=None): """ @type filter_layer_names: exclusive layer names list ie, only these layers to be returned """ layer_names = [] hLayer = vs.FLayer() # Use a while loop and the NextLayer() function to iterate through all the sheet layers in the document while hLayer != None: layer_names.append(hLayer) if vs.GetObjectVariableInt(hLayer, 154) == 2: layer_name = vs.GetLName(hLayer) if excluded_layer_names: if layer_name not in excluded_layer_names: layer_names.append(layer_name) else: layer_names.append(layer_name) hLayer = vs.NextLayer(hLayer) return layer_names then when you run the iteration, you provide the list of sheet names you want excluded: # Iterate through all sheet layers in the current document # Say you want to exclude sheets 01, 05, 10, 12 for layer in list_sheet_layer_names(['01', '05', '10', '12']): # Define criteria strings to find title blocks and viewports on the current layer titleblock_crit_str = f"(((L='{layer}') & (PON='Title Block Border')))" viewports_crit = f"(((L='{layer}') & (T=VIEWPORT)))" # Use the get_objects_from_criteria() function to get lists of title blocks and viewports on the current layer titleblocks = get_objects_from_criteria(titleblock_crit_str) viewports = get_objects_from_criteria(viewports_crit) <<< RESET OF CODE >> Quote Link to comment
Neda Roohnia Posted June 2, 2023 Author Share Posted June 2, 2023 4 hours ago, twk said: You know what, I misunderstood your question. You're wanting an excluded list. We'll revise the 'list_sheet_layer_names' function that accepts a list of sheets to be 'excluded' as a parameter. # Define a function to list the names of all sheet layers in the current document def list_sheet_layer_names(excluded_layer_names=None): """ @type filter_layer_names: exclusive layer names list ie, only these layers to be returned """ layer_names = [] hLayer = vs.FLayer() # Use a while loop and the NextLayer() function to iterate through all the sheet layers in the document while hLayer != None: layer_names.append(hLayer) if vs.GetObjectVariableInt(hLayer, 154) == 2: layer_name = vs.GetLName(hLayer) if excluded_layer_names: if layer_name not in excluded_layer_names: layer_names.append(layer_name) else: layer_names.append(layer_name) hLayer = vs.NextLayer(hLayer) return layer_names then when you run the iteration, you provide the list of sheet names you want excluded: # Iterate through all sheet layers in the current document # Say you want to exclude sheets 01, 05, 10, 12 for layer in list_sheet_layer_names(['01', '05', '10', '12']): # Define criteria strings to find title blocks and viewports on the current layer titleblock_crit_str = f"(((L='{layer}') & (PON='Title Block Border')))" viewports_crit = f"(((L='{layer}') & (T=VIEWPORT)))" # Use the get_objects_from_criteria() function to get lists of title blocks and viewports on the current layer titleblocks = get_objects_from_criteria(titleblock_crit_str) viewports = get_objects_from_criteria(viewports_crit) <<< RESET OF CODE >> Thanks a lot! I tried this, I included those sheetlayer names to be excluded, but still did not work. Very strange!! Quote Link to comment
twk Posted June 2, 2023 Share Posted June 2, 2023 Apologies looks like there was an extra line after the 'while' call. correct below: # Define a function to list the names of all sheet layers in the current document def list_sheet_layer_names(excluded_layer_names=None): """ @type filter_layer_names: exclusive layer names list ie, only these layers to be returned """ layer_names = [] hLayer = vs.FLayer() # Use a while loop and the NextLayer() function to iterate through all the sheet layers in the document while hLayer != None: if vs.GetObjectVariableInt(hLayer, 154) == 2: layer_name = vs.GetLName(hLayer) if excluded_layer_names: if layer_name not in excluded_layer_names: layer_names.append(layer_name) else: layer_names.append(layer_name) hLayer = vs.NextLayer(hLayer) return layer_names 1 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.