Jump to content

to automate updating titleblock w/ viewport scale


Recommended Posts

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! 

 

Link to comment

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 by twk
  • Like 1
Link to comment

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}')

 

Link to comment
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}')

 

 

Link to comment
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!!

Link to comment

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}")

 

Link to comment
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! 

Link to comment
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!

Link to comment
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!

  • Like 1
Link to comment
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..

  • Like 1
Link to comment

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

  • Like 3
Link to comment
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!

 

Link to comment

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! 

  • Like 2
Link to comment
  • 4 weeks later...
  # 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)

 

  • Like 2
Link to comment
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.

Link to comment

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

 

  • Like 2
Link to comment
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!

Link to comment

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

 

  • Like 1
Link to comment
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 by Neda Roohnia
Link to comment

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

 

 

 

Link to comment
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!!

Link to comment

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

 

  • Like 1
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...