Line 2 Window Frame

# 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].co-vs[0].co, vs[-1].co-vs[0].co)
    yield np.array(vs[0].co) 
    yield np.array(vs[0].co) + hw*crossProduct(n, vs[1].co - vs[0].co)
    yield np.array(vs[0].co) + hw*crossProduct(n, vs[1].co - vs[0].co) + hh*n
    yield np.array(vs[0].co) + hh*n
    for i in range(1,len(vs)-1):
        # U = an edge of sliced square
        p0 = hw*crossProduct(n, vs[i].co - vs[i-1].co)
        p1 = hw*crossProduct(n, vs[i+1].co - vs[i].co)
        w = (p0+p1)/2.0
        len_w = np.linalg.norm(w)
        w = w*(hw*hw/len_w/len_w)
        yield np.array(vs[i].co)
        yield np.array(vs[i].co) + w
        yield np.array(vs[i].co) + w + hh*n
        yield np.array(vs[i].co) + hh*n
    yield np.array(vs[-1].co)
    yield np.array(vs[-1].co) - hw*crossProduct(n, vs[-2].co - vs[-1].co)
    yield np.array(vs[-1].co) - hw*crossProduct(n, vs[-2].co - vs[-1].co) + hh*n
    yield np.array(vs[-1].co) + 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)        

def genEdges(l):
    for i in range(l-1):
        yield (i, i+1)
    
def main(hw, hh):
#    bpy.ops.object.mode_set(mode='EDIT', toggle=False)
    o0 = bpy.context.scene.objects.active
    loc0 = o0.location
    m0 = o0.data
    bm0 = bmesh.from_edit_mesh(m0)
    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.location = loc0
#    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)
#