Line 2 Window Frame Looped

# let u, v vectors on the plane. b the origin on it.
# let a a point off plane. and n a normal of the plane.
import sys
import bmesh
import numpy as np

def mapOnPlane(a, b0, b1, b2):
    u = np.array([b1[0]-b0[0], b1[1]-b0[1], b1[2]-b0[2]])
    v = np.array([b2[0]-b0[0], b2[1]-b0[1], b2[2]-b0[2]])
    n = np.cross(u, v)
    tX = np.array([n, u, v])
    X = np.array([tX[:,0], tX[:,1], tX[:,2]])
    print(X)
#    X = np.array([[n[0], u[0], v[0]], [n[1], u[1], v[1]], [n[2], u[2], v[2]]])
#    print(X)
    Y = np.array([b0[0]-a[0], b0[1]-a[1], b0[2]-a[2]])
#    print(u,v,n,X,Y)
    s = np.linalg.solve(X, Y)
    return (a[0] + s[0]*n[0], a[1] + s[0]*n[1], a[2] + s[0]*n[2])

def pressLine():
    if bpy.ops.object.mode_set.poll():
        bpy.ops.object.mode_set(mode='EDIT', toggle=False)
    ao = bpy.context.scene.objects.active
    bm = bmesh.from_edit_mesh(ao.data)
    vs = bm.verts
    l = len(vs)
    print("lenth = "+str(l))
    if l<4:
        sys.exit()
    b = []
    b.append(vs[1])
    b.append(vs[-1])
    b.append(vs[0])
    k=0
    for i in range(l):
        if bm.verts[i].select and k<3:
            b[k] = vs[i]
            k += 1
            print(i)
    for i in range(l):
        print(i, vs[i].co)
        vs[i].co = mapOnPlane(vs[i].co, b[0].co, b[1].co, b[2].co)
        print(i, vs[i].co)
    ao.data.update()
    
def crossProduct(u, v):
#    print(u,v)
    p = np.cross(u, v)
    q = p/np.linalg.norm(p)
#    print(q)
    return (q)

# hw half width
def genWs(hw, hh, vs):
    n = crossProduct(vs[1][1]-vs[0][1], vs[-1][1]-vs[0][1])
    for i in range(len(vs)):
        if i < len(vs)-1:
            p0 = hw*crossProduct(n, vs[i][1] - vs[i-1][1])
            p1 = hw*crossProduct(n, vs[i+1][1] - vs[i][1])
        else:
            p0 = hw*crossProduct(n, vs[i][1] - vs[i-1][1])
            p1 = hw*crossProduct(n, vs[0][1] - vs[i][1])
        # U = an edge of sliced square
        w = (p0+p1)/2.0
        len_w = np.linalg.norm(w)
        w = w*(hw*hw/len_w/len_w)
        yield np.array(vs[i][1])
        yield np.array(vs[i][1]) + w
        yield np.array(vs[i][1]) + w + hh*n
        yield np.array(vs[i][1]) + hh*n

def genFaces(l):
    for i in range(l-1):
        # k is the origin of each node
        k = 4*i
        for j in range(3):
            m = k+j
            yield (m, m+4, m+1)
            yield (m+4, m+1, m+5)
        m = k+3
        yield (m, m+4, k)
        yield (m+4, k, k+4)
    # extra faces for the loop
    k+=4
    for j in range(3):
        yield (k+j, j, k+j+1)
        yield (j, k+j+1, j+1)
    yield (k+3, 3, k)
    yield (3, k, 0)
    
def genEdges(l):
    for i in range(l-1):
        yield (i, i+1)
    
# if you want to change the vertices order, 
# apply them to bmesh prior to the function.
def main(hw, hh, bm=None):
#    bpy.ops.object.mode_set(mode='EDIT', toggle=False)
    o0 = bpy.context.scene.objects.active
    m0 = o0.data
    if not bm:
        bm = bmesh.from_edit_mesh(m0)
    l = [(v.index, v.co) for v in bm.verts]
    vs = []
    for i in range(len(l)):
        for j in range(len(l)):
            if l[j][0] == i:
                vs.append(l[j])
#    vs = bm0.verts
    listWs = list(genWs(hw, hh, vs))
    listFaces = list(genFaces(len(vs)))
    listEdges = list(genEdges(len(vs)))
    #
    bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
#    bpy.context.scene.objects.unlink(o0)
#
    m1 = bpy.data.meshes.new('cyWindowFrameMesh')
    o1 = bpy.data.objects.new('cyWindowFrame', m1)
    o1.matrix_basis = o0.matrix_basis
    o1.matrix_local = o0.matrix_local
    o1.matrix_parent_inverse = o0.matrix_parent_inverse
    o1.matrix_world = o0.matrix_world
    o1.location = o0.location
#    m1.from_pydata(listWs, listEdges, [])
    m1.from_pydata(listWs, [], listFaces)
    m1.update()
#    bpy.ops.object.select_pattern(pattern="cyWindowFrame")
#
#    if bpy.ops.object.mode_set.poll():
    bpy.context.scene.objects.link(o1)
#