def exportNURBSCurve(curve, bbox=[(0,0), (1,1)]):
    file_str = io.StringIO()
    
    degree = curve.M
    assert(degree <= 3)
    assert(curve.prop3 == 1)

    # print(curve)

    # first convert nurbs to bezier
    # TODO: assume the knot sequence has knot multiplicty degree + 1 at both end
    b_knot, b_cpts = nurbs2bezier(curve.T[1:-1], [np.array(p) for p in curve.control_points], degree)

    for p in b_cpts:
            p[0:2] -= np.array(bbox[0])
            p[0] /= bbox[1][0] - bbox[0][0]
            p[1] /= bbox[1][1] - bbox[0][1]
        

    file_str.write("M {},{}".format(b_cpts[0][0], b_cpts[0][1]))

    first = True
    
    for i in range((len(b_cpts) - 1) // degree):
        print("-----")

        cpts = []
        for j in range(degree + 1):
            newp = b_cpts[i*degree + j]
            cpts.append(newp)

        if degree == 1:
            file_str.write(" L {},{}".format(cpts[1][0], cpts[1][1]))
            continue
        
        if degree == 2:
            cpts = degRaiseFrom2(cpts)

        for i,p in enumerate(cpts):
            if first:
                first = False
                file_str.write(" C ")
            elif i != 0:
                file_str.write(" {},{}".format(p[0], p[1]))

    return  file_str.getvalue()
def exportNURBSSurface(surface):
    file_str = io.StringIO()
    
    degu = surface.M1
    degv = surface.M2

    #print(surface)

    # first convert nurbs to bezier
    # TODO: assume the knot sequence has knot multiplicty degree + 1 at both end
    #print(len(surface.control_points), len(surface.W))
    cpts = np.array([np.array([surface.control_points[i][0],
                      surface.control_points[i][1],
                      surface.control_points[i][2],
                      surface.W[i]]) for i in range(len(surface.W))])

    cpts = cpts.reshape([ surface.K2 + 1, surface.K1 + 1, 4])

    # 1rd direction
    b_knot_u, b_cpts = nurbs2bezier(surface.T1[1:-1], [cpts[:,i] for i in range(surface.K1 + 1)], degu)
    cpts = np.array(b_cpts)
    b_knot_v, b_cpts = nurbs2bezier(surface.T2[1:-1], [cpts[:,i] for i in range(surface.K2 + 1)], degv)
    cpts = np.array(b_cpts)
    
    uvbbox = [(surface.U0, surface.V0), (surface.U1, surface.V1)]

    total_bicubic_piece = 0
    
    # TODO: assume the nurbs curve is indeed in bezier form
    for piece_v in range((cpts.shape[0] - 1)//degv):
        v_base = b_knot_v[piece_v * degv]
        v_end = b_knot_v[piece_v * degv + degv]
        for piece_u in range((cpts.shape[1] - 1)//degu):
            u_base = b_knot_u[piece_u * degu]
            u_end = b_knot_u[piece_u * degu + degu]

            bcpts = np.zeros([degv + 1, degu + 1, 6])
            
            for i in range(degv + 1):
                for j in range(degu + 1):
                    idx_v = i + degv * piece_v
                    idx_u = j + degu * piece_u

                    p = cpts[idx_v][idx_u]

                    #file_str.write("v {} {} {} {}\n".format(p[0], p[1], p[2], p[3]))

                    uv = np.array((u_base + j / degu * (u_end - u_base), v_base + i / degv * (v_end - v_base)))
                    uv -= np.array(uvbbox[0])
                    uv[0] /= (uvbbox[1][0] - uvbbox[0][0])
                    uv[1] /= (uvbbox[1][1] - uvbbox[0][1])
                    
                    #file_str.write("vt {} {}\n".format(uv[0], uv[1]))

                    bcpts[i][j] = np.array([p[0], p[1], p[2], p[3], uv[0], uv[1]])

                    # print(xyz,w,uv)

            # convert bezier patch to bicubic
            vpiece = 1 if degv <= 3 else 3
            upiece = 1 if degu <= 3 else 3

            _bcpts = convert2Cubic([bcpts[:,i] for i in range(degu+1)])
            bcpts = np.array(_bcpts)
            _bcpts = convert2Cubic([bcpts[:,i] for i in range(degv+1)])
            bcpts = np.array(_bcpts)

            for i in range(vpiece):
                for j in range(upiece):
                    total_bicubic_piece += 1
                    for k in range(4):
                        for l in range(4):
                            p = bcpts[i*3 + k][j*3 + l]
                            
                            file_str.write("v {} {} {} {}\n".format(p[0], p[1], p[2], p[3]))
                            file_str.write("vt {} {}\n".format(p[4], p[5]))
                    
            
                    
    idx = 1
    # for piece_v in range((cpts.shape[0] - 1)//degv):
    #     for piece_u in range((cpts.shape[1] - 1)//degu):
    #         file_str.write("p {} {}\n".format(degu, degv))
    #         for i in range((degu + 1)*(degv + 1)):
    #             file_str.write("{}/{}\n".format(idx, idx))
    for i in  range(total_bicubic_piece):
        file_str.write("p {} {}\n".format(3, 3))
        for i in range(16):
            file_str.write("{}/{}\n".format(idx, idx))
            idx+=1

    return file_str.getvalue()