Creating a script to delete paths outside the metrics box

I am currently working on a script that deletes all paths outside of the metrics box. Unfortunately, it is not functioning as expected at the moment. I would greatly appreciate any assistance in identifying the issue.

If anyone has experience with similar tasks or can offer any advice, it would be incredibly helpful. Here’s the code I wrote.

import GlyphsApp

font = Glyphs.font

selected_layers = font.selectedLayers  # Get currently selected layers
selected_glyphs = [layer.parent for layer in selected_layers]  # Get parent glyphs of selected layers

for glyph in selected_glyphs:  # Process each selected glyph
    for layer in glyph.layers:
        bounds = layer.bounds  # Get the metrics (bounds) of the layer
        x_min, y_min = bounds.origin.x, bounds.origin.y
        x_max, y_max = x_min + bounds.size.width, y_min + bounds.size.height
        
        # Delete shapes located outside the metrics
        for shape in layer.shapes[:]:  # Iterate over a copied list to safely remove items
            remove_shape = False  # Variable to track whether the shape should be removed
            
            # Iterate over the shape's paths
            for path in shape.paths:
                for node in path.nodes:  # Iterate through the nodes of each path
                    x, y = node.position.x, node.position.y  # Get x, y coordinates of the node
                    
                    # If a node is outside the metrics, mark the shape for removal
                    if x < x_min or x > x_max or y < y_min or y > y_max:
                        remove_shape = True
                        break  # Stop checking if any node is out of bounds
                if remove_shape:
                    break  # Stop checking further if shape is marked for removal

            if remove_shape:
                layer.shapes.remove(shape)  # Remove shape located outside the metrics


Your code is fine except for the last line. You cannot delete a shape while you’re iterating over the shapes. And you would not delete it this way. I suggest to change that last line into adding the index of that shape to a list. And outside of the loop you go through that index list in reverse and delete the shapes like this:

for idx in sorted(indexes_for_deletion, reverse=True):
    del layer.shapes[idx]

I’m getting an error: ‘GSPath’ object has no attribute ‘paths’. Does this mean I haven’t defined the path correctly?

That is the error for for path in shape.paths:. The shape does not have paths. The layer has paths. So you want to check if the bounds of the shape exceed the box:

left = shape.bounds.origin.x
right = shape.bounds.origin.x + shape.bounds.size.width
bottom = shape.bounds.origin.y
top = shape.bounds.origin.y + shape.bounds.size.height

Then you can see if left < x_min, etc.

Get rid of the three lines for path..., for node... and x, y =...

1 Like

Thank you so much! I’ll try it as you suggested. You’re a genius!