I have imported an SVG keyboard layout into Blender (2.83), which arrives as filled curves in the XY plane.

wireframe of svg import

For each key, after converting the curve to mesh, I have managed to dissolve some edges with bmesh.

    # tris to ngons, separating the bottom from the top
    edges = [e for e in bm.edges if e.verts[0].co.y != e.verts[1].co.y]
    bmesh.ops.dissolve_edges(bm, edges=edges)

wireframe of mesh with ngons

This leaves each key with a quad and a polygon, or ngon, with either 5 or 6 vertices/edges.

ngons in edit mode

I want to subdivide the ngons "vertically" using the existing vertices to make quads (2 quads if 5 verts, 3 quads if 6 verts). I have worked out how to find them, or delete the ngon and keep the edges but am no closer to a solution.

    for f in bm.faces:
        if len(f.verts) > 4:
            bmesh.ops.delete(bm, geom=[f], context='FACES_ONLY')

In one version of the SVG I manually added extra vertices at the bottom to help create the required edges, but wonder if this useful or pointless (bad pun).

How do I convert these polygons (ngons) with more than 4 sides to quads, adding only vertical edges?


Verts of non-boundary edge.

enter image description here

Assuming the white keys are the mesh, where there is an ngon is at the ends of a non boundary edge

Test script below, finds ngons, bisects using YZ (keys aligned along x axis) plane at boundary edge vert coordinates, removes doubles, and repeats until there are no more ngons.

An additional test to make sure the other two connected edges are at an angle of around 90 degrees has been added. (See below)

import bpy
import bmesh

context = bpy.context
ob = context.edit_object
me = ob.data
bm = bmesh.from_edit_mesh(me)

ngons = [f for f in bm.faces if len(f.edges) > 4]

while ngons:
    f = ngons.pop()
    def test(v, edge):
        if len(v.link_edges) == 3:
            e0, e1 = [e for e in v.link_edges if e.is_boundary]
            ev0 = (e0.verts[0].co - e0.verts[1].co)
            ev1 = (e1.verts[1].co - e1.verts[0].co)
            return abs(ev0.dot(ev1)) < 0.1
        return False
    # find verts of non boundary edge
    verts = [v for e in f.edges 
            if not e.is_boundary
            for v in e.verts if test(v, e)]
    for v in verts:
        geom = bmesh.ops.bisect_plane(
                geom=[f] + f.edges[:] + f.verts[:],
                plane_no=((1, 0, 0)),
    ngons = [f for f in bm.faces if len(f.edges) > 4]          

  • $\begingroup$ This works for one bisect if I dont use the while loop, but if I use the loop I get infinite loops. Still probing... $\endgroup$ – koober Oct 25 '20 at 10:20
  • 1
    $\begingroup$ Allow me to apologize for my uncalled for upvote comment. I have removed it. Using is_boundary found me the answer and you deserve a point for it, rather than me adding a similar answer. And dozens of your answers have helped me in the past Having eventually figured out my issues it wasnt worth uploading a blend and I thought I should share my findings for future readers. $\endgroup$ – koober Oct 30 '20 at 14:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.