New script. Vertex to Face. Check Out.

Hi everybody. Yesterday I wrote a script of which I was thinking for quite a few days. Select some unconnected vertices of a mesh then run this script and bingo, they are connected. (Remember this is an alpha version)
See the pics below.
Before http://img128.imageshack.us/img128/3015/blownoffcylinder8ul.jpg
After http://img152.imageshack.us/img152/5429/recapedcylinder4jz.jpg

Before http://img152.imageshack.us/img152/9237/rapturedcylinder4oa.jpg
After http://img107.imageshack.us/img107/6444/fixedcylinder7bm.jpg

Before http://img107.imageshack.us/img107/7510/rapturedplane7rb.jpg
After http://img93.imageshack.us/img93/1579/fixedplane3im.jpg

In above pic u can see that this program only makes tris no quads. This will be added later. For more documentation see the code. Now the code.


#!BPY

"""
Name: 'Vertices to Faces v apha1'
Blender: 241
Group: 'Mesh'
Tooltip: 'All selected connected/unconnected vertices are cennected and faces are build.'
"""

__author__ = "Apple Grew"
__email__ = ["Apple Grew, [email protected] (remove the dashes)"]
__version__="alpha1"

__bpydoc__ = """\
Usage: Select the vertices of the mesh which u want to linka and run this script.

Notes:
1)This is aplha version of script.
2) This is designed to work on planes (maybe flat or curved).
3) This works best in places where there is symmetry and there are less obstruction between
the selected vertices.
4) This only makes tris not quads.
5) The script sees ONLY the selected vertices and tries to connect all of them together,
hence if some of the vertices lie someplace far (connected with other vertices) then also
they will be linked together, jumping over all the vertices lying in-between.
"""

# --------------------------------------------------------------------------
# Vertices to Faces
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# -------------------------------------------------------------------------- 

from Blender import Object, Draw, Window, NMesh
import math

DEBUG=False
INFINITE=1e308 #on my machine this was the largest no. (approx) which Pyhton could handle.

def error(msg):
    Draw.PupMenu("Error%t|"+msg)

def calStdDeviation(X): #where X is a List of elements of whose standard
    #deviation is to be found.
    if len(X)==0:
        return 0
    avg=0
    for xi in X:
        avg=avg+xi
    avg=avg/len(X)
    
    sqSum=0
    for xi in X:
        sqSum=sqSum+ (xi-avg)**2
    
    return math.sqrt(sqSum/len(X))

def calDis(v1,v2): #calculates distance between two vertices.
    v1=v1.co #getting coordinate.
    v2=v2.co
    return math.sqrt((v1.x-v2.x)**2+(v1.y-v2.y)**2)

def rationalizeDis(d): #searches for the largest no. in list d then divides all
    #elements by this no.
    if len(d)==0:
        return []
    BIG=d[0]
    #searching for the largest no.
    for x in d:
        if x>BIG:
            BIG=x

    if BIG==0:
        return
    
    #updating the list.
    for i in range(len(d)):
        d[i]=d[i]/BIG
    
    return d
    
    ##checks wheather vertx v1 can connect with v2. (note: vi1 and vi2 are
    ##indices not the obeject itself.
    ##2 vertices are not connectable if while connecting them it crosses
    ##another edge.
def isConnectable(vert,vd,vi1,vi2):
    for vli in range(len(vd)):
        #if vli==vi1 or len(vd[vli])==0:
        if len(vd[vli])==0:
            continue
        for i in vd[vli]:
            x1=vert[vli].co.x
            y1=vert[vli].co.y
            
            x2=vert[i].co.x
            y2=vert[i].co.y
            
            x3=vert[vi1].co.x
            y3=vert[vi1].co.y
            
            x4=vert[vi2].co.x
            y4=vert[vi2].co.y
            
            if (x2-x1)==0:
                k1=INFINITE
            else:
                k1=(y2-y1)/(x2-x1)
            if (x4-x3)==0:
                k2=INFINITE
            else:
                k2=(y4-y3)/(x4-x3)
            if k1==k2:
                continue
            
            if (x1,y1)==(x3,y3) or (x1,y1)==(x4,y4)\
            or (x2,y2)==(x3,y3) or (x2,y2)==(x4,y4):
                continue
            
            x=(y3-y1+k1*x1-k2*x3)/(k1-k2)
            y=y1+k1*(x-x1)
            
            flag=0
            if x1<x2:
                X1,X2=x1,x2
            else:
                X1,X2=x2,x1
            if y1<y2:
                Y1,Y2=y1,y2
            else:
                Y1,Y2=y2,y1
            if X1<=x and x<=X2 and Y1<=y and y<=Y2:
                if DEBUG:
                    print '+++no Connection for '+str(vi1)+' and '+str(vi2)+'+++'
                    print '+++>x within x1x2 of vert.s '+str(vli)+' and '+str(i)
                flag=1
            
            if x3<x4:
                X1,X2=x3,x4
            else:
                X1,X2=x4,x3
            if y3<y4:
                Y3,Y4=y3,y4
            else:
                Y3,Y4=y4,y3
            if X1<x and x<X2 and Y1<=y and y<=Y2:
                if DEBUG:
                    print '+++no Connection for '+str(vi1)+' and '+str(vi2)+'+++'
                    print '+++>x within x1x2 of vert.s '+str(vli)+' and '+str(i)
                flag+=1
            
            if flag==2:
                return False
    return True

def vert2face():
    selection = Object.GetSelected()
    if len(selection) == 0:
        error('No object selected')
        return
        
    if len(selection)>1:
        error('Select only one object')
        return
    
    if selection[0].getType() != 'Mesh':
        error('Only mesh are allowed.')
        return
    
    obj=selection[0].getData() #getting the object.
    
    #getting list of all selected vertices.
    vert=[]
    for v in obj.verts:
        if v.sel:
            vert.append(v)
    
    #Hence for revision.
    #ob is the mesh object.
    #vert is the list of selected vertices.
    
    if DEBUG:
        print "==Vertices data dump=="
        i=0
        for v in vert:
            i=i+1
            print "vert "+str(i)+" ("+str(v.co.x)+","+str(v.co.y)+")"
        print("==Dump complete==")
    
    #calculating distances of each vertice with every other.
    #c=[]
    stdDev=[]
    for i in range(len(vert)):
        r=[]
        for j in range(len(vert)):
            if i==j: continue
            r.append(calDis(vert[i],vert[j]))
        r=rationalizeDis(r)
        if r is None:
            error('Maybe faulty mesh. Two vertices in the same location.')
            return
        stdDev.append([calStdDeviation(r),i])
        #c.append(r)
    
    #bubble sorting stdDev according to increasing values.
    for i in range(len(stdDev)):
        for j in range(i+1,len(stdDev)):
            if stdDev[i][0]>stdDev[j][0]:
                t=stdDev[i]
                stdDev[i]=stdDev[j]
                stdDev[j]=t
    
    if DEBUG:
        print '@@stdDev dump@@'
        for s in stdDev:
            print s
        print '@@Dump complete@@'
    
    #sorting vert according to increasing stdDev.
    tvert=[]
    for sd in stdDev:
        tvert.append(vert[sd[1]])
    vert=tvert
    tvert=[]#clearing it
    stdVert=[]#clearing it
    
    vd=[] #stores index of all the vertices a particular vertex is connected to.
    #first searching and updating vd of already connected vertices.
    for i in range(len(vert)):
        r=[]
        for j in range(i+1,len(vert)):
            if obj.findEdge(vert[i],vert[j]) is not None:
                r.append(j)
        vd.append(r)
    if DEBUG:
        print '**vd dump (of already connected vertices)**'
        for v in vd:
            print v
        print '**Dump complete**'
    
    #now connecting vertices.
    for i in range(len(vert)):
        for j in range(i+1,len(vert)):
            if vd[i].count(j)==0 and isConnectable(vert,vd,i,j):
                vd[i].append(j)
    
    if DEBUG:
        print '**vd dump (Final)**'
        for v in vd:
            print v
        print '**Dump complete**'
    
    #making faces.:-)
    vertexList=[]
    for vi in range(len(vd)):
        vil=vd[vi]
        for i in vil:
            for j in vil:
                if i==j:
                    continue
                if vd[i].count(j)!=0: #means vert[i] is connected with vert[j].
                    vertexList.append([vert[vi],vert[i],vert[j]])
    if DEBUG: print '++vertexList dump++'
    face=[]
    for vL in vertexList:
        face.append(NMesh.Face(vL))
        if DEBUG:
            print [(vL[0].co.x ,vL[0].co.y),(vL[1].co.x ,vL[1].co.y),(vL[2].co.x ,vL[2].co.y)]
    if DEBUG: print '++Dump complete++'
    
    #updating obj.
    #obj.addEdgesData()
    for f in face:
        obj.addFace(f)
    
    obj.update()


##calling vert2face##
Window.DrawProgressBar(0.0, 'Vertices to Faces v apha1 ')
print 'Vertices to Faces v apha1. Processing...'
is_editmode = Window.EditMode()
if is_editmode: Window.EditMode(0)
vert2face()
if is_editmode: Window.EditMode(1)
print 'Done!'
Window.DrawProgressBar(1.0, '')

Do write ur comments. And someone more knowledgeable if u think this script is worth ur time then help me improve it.
I hope this is useful. :expressionless:

actually, it created triangles leaving the quads alone. and on the top right the purple color is because there’s a selected triangle overlapping a non-selected quad.

Thanks. I did see them but was not sure. I pulled the vertices but no underlaying faces were seen. Now I remember that for 4-vertices faces if one vertex is pulled out of the plane then the face fold at the middle and hence it was not noticeable to me then. Actually I assumed that whenever we make a new face between vertices then the old one might be deleted. Now it seems unreasonable. A vertex can be part of many faces and blender does not remove (or check) the hidden face (might that be intended by the creator).

what about shift+f?

this is the msh to be fixeds.

http://img91.imageshack.us/img91/6949/cylinderopen5se.jpg

after shift+f

http://img60.imageshack.us/img60/2961/cylindershiftf5lr.jpg

After using Vert2Face
http://img70.imageshack.us/img70/959/cylindermyscript0ei.jpg

Note the difference. It tries to connect faces the most symmetrical way.

Nice script man!
Probably worth implimenting in Blender/C
would be a good first project :slight_smile:

Hi. Thanks! :smiley: Atlast some appretiation. I am currently updating the script. The script will now make quad faces whenever possible and will make quads which are most square like. Furthermore I will correct the bug pointed out by z3r0 d.

Very Nice! Re-implementing this in C would be an excellent way to extend the functionality of the Fill function.

Hi thanks once again. I will first create its next version in python that way it will be easy to write and test then I will implement it in C, but for that I need help because I don’t know how to do that. I am rather clueless. Point me to some url of help.

Just replying to say that I really like what you’re doing.
Very nice addition to shift-f.

Just came back to say hello. I am currently improving the script just as I said I will. I don’t know when will I be able to post the new script, because of my on-goin practical exams & the coming end-sem exam. Wish me luck & do post any reply of information or appreciation atleast. Thank u. :-?

script can come in handy…

Tanks for the script. shift-F not always runs as I wish.

Yes cool script, I also think the shift+f needs some attention and your script is well on the way to solving that, I will watch for your next version goodluck with your exams :wink:

Version alpha2
I am still calling this alpha since it may still be quite buggy.

Now for some demo of the script:-
Before
http://images6.theimagehosting.com/raptured%20cylinder.jpg

After shift+f
http://images6.theimagehosting.com/cylinder%20rapture%20shiftf-alpha2.JPG
Notice the darker purple faces. They have been formed due to overlapping faces.

After Vert2Face
http://images6.theimagehosting.com/cylinder%20rapture%20fixed-alpha2.JPG

Before
http://images6.theimagehosting.com/sphere%20top%20blownup-alpha2.JPG

After shift+f
http://images6.theimagehosting.com/sphere%20shiftf-alpha2.JPG
Notice that the centre vertex has not been connected.

After Vert2Face
http://images6.theimagehosting.com/sphere%20top%20filled-alpha2.JPG

Before
http://images6.theimagehosting.com/raptured%20plane-alpha2.jpg

After shift+f
http://images6.theimagehosting.com/shiftf%20plane-aplha2.JPG
Here also note that there are some double faces on top of each other.

After Vert2Face
http://images6.theimagehosting.com/fixed%20plane-aplha2.JPG

After Vert2Face (when it is instructed to make only triangles)
http://images6.theimagehosting.com/fixed%20plane%20%28no%20quad%29-aplha2.JPG

Before
http://images6.theimagehosting.com/wavy%20plane%20raptured-alpha2.JPG

After shift+f
http://images6.theimagehosting.com/wavy%20plane%20shiftf.JPG

After Vert2Face
http://images6.theimagehosting.com/wavy%20plane%20-alpha2.JPG

Using Vert2Face, but now after rotating (in edit mode) all the vertices 90 degree so as to make the mesh vertcal along the local z-axis.
http://images6.theimagehosting.com/wavy%20plane%20faultly%20fixed%20when%20vertical%20along%20z-axis%20-alpha2.JPG
Now we see that the script has not worked properly. This is because of a limitation in the present code (which I hope to remove in future version). Actually the script only ‘sees’ the values of the x & y coordinates not the z coordinate. Hence it is like looking at the mesh along its local z-axis. Hence if u have a plane that is vertical along the local z-axis then it will look just like a line to the script.

Well now are u interested in having this script? If yes then look in my next post for its code.

Version alpha2 code

#!BPY

"""
Name: 'Vertices to Faces v alpha2'
Blender: 241
Group: 'Mesh'
Tooltip: 'All selected connected/unconnected vertices are cennected and faces are build.'
"""

__author__ = "Apple Grew"
__email__ = ["Apple Grew, [email protected] (remove the dashes)"]
__version__="alpha2"

__bpydoc__ = """\
Usage: Select the vertices of the mesh which u want to link and run this script.
       Click on 'Make quads?' if u want that quads are made wherever possible, else
       move your mouse out of this dialog box (now only triangles will be made).

Notes:
1) This is alpha version of script.
2) This is designed to work on planes (maybe flat or curved).
3) There is a serious limitation right now. The script only 'sees' the values of the x & y coordinates
   not the z coordinate. Hence it is like looking at the mesh along its local z-axis. Hence if u have a
   plane that is vertical along the local z-axis then it will look just like a line to the script. This
   may result in unexpected results.
"""

# --------------------------------------------------------------------------
# Vertices to Faces
# --------------------------------------------------------------------------
# Author: Apple Grew
# Acknowledgement: Rohit Singh for the basic algo of tris to quad.
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# -------------------------------------------------------------------------- 

from Blender import Object, Draw, Window, NMesh, Mathutils
import math

DEBUG=False
INFINITE='infinite'

def DrawProgressBar(value,text):
    #Window.DrawProgressBar(value,text)
    #print text+' ' +str(value*100)+'%'
    pass
    
def error(msg):
    Draw.PupMenu("Error%t|"+msg)

def calStdDeviation(X): #where X is a List of elements of whose standard
    #deviation is to be found.
    if len(X)==0:
        return 0
    avg=0
    for xi in X:
        avg=avg+xi
    avg=avg/len(X)
    
    sqSum=0
    for xi in X:
        sqSum=sqSum+ (xi-avg)**2
    
    return math.sqrt(sqSum/len(X))

def calDis(v1,v2): #calculates distance between two vertices.
    v1=v1.co #getting coordinate.
    v2=v2.co
    return math.sqrt((v1.x-v2.x)**2+(v1.y-v2.y)**2)

def isLinesIntersecting(v1,v2, v3,v4):
    x1=v1.co.x
    y1=v1.co.y
    
    x2=v2.co.x
    y2=v2.co.y
    
    x3=v3.co.x
    y3=v3.co.y
    
    x4=v4.co.x
    y4=v4.co.y
    
    if (x1,y1)==(x3,y3) or (x1,y1)==(x4,y4)\
    or (x2,y2)==(x3,y3) or (x2,y2)==(x4,y4):
        return False
    
    if (x2-x1)==0:
        k1=INFINITE
    else:
        k1=(y2-y1)/(x2-x1)
    if (x4-x3)==0:
        k2=INFINITE
    else:
        k2=(y4-y3)/(x4-x3)
    if k1==k2:
        return False
    
    if k1==INFINITE:
        x=x1
        y=y3+k2*(x-x3)
    else:
        if k2==INFINITE:
            x=x3
        else:
            x=(y3-y1+k1*x1-k2*x3)/(k1-k2)
        y=y1+k1*(x-x1)
##    if DEBUG: print 'Pt. of Intersection (x,y): '+str((x,y))
    
    flag=0
    if x1<x2:
        X1,X2=x1,x2
    else:
        X1,X2=x2,x1
    if y1<y2:
        Y1,Y2=y1,y2
    else:
        Y1,Y2=y2,y1
    if X1<=x and x<=X2 and Y1<=y and y<=Y2:
##        if DEBUG:
##            print '+++[no Connection for '+str(vi1)+' and '+str(vi2)+'+++'
##            print '+++>x within x1x2 of vert.s '+str(vli)+' and '+str(i)
        flag=1
    
    if x3<x4:
        X1,X2=x3,x4
    else:
        X1,X2=x4,x3
    if y3<y4:
        Y1,Y2=y3,y4
    else:
        Y1,Y2=y4,y3
    if X1<=x and x<=X2 and Y1<=y and y<=Y2:
##        if DEBUG:
##            print '+++]no Connection for '+str(vi1)+' and '+str(vi2)+'+++'
##            print '+++>x within x1x2 of vert.s '+str(vli)+' and '+str(i)
        flag+=1
    
    if flag==2:
        return True
    else:
        return False

##checks wheather vertx v1 can connect with v2. (note: vi1 and vi2 are
##indices not the obeject itself.
##2 vertices are not connectable if while connecting them it crosses
##another edge.
##edges is a list of all edges present in the object even if none of its verts are selected.
def isConnectable(vert,vd,doNotConnect,Edges,vi1,vi2):
    for dnC in doNotConnect:
        if dnC==[vert[vi1],vert[vi2]] or dnC==[vert[vi2],vert[vi1]]:
            return False
    
    for vli in range(len(vd)):
        if len(vd[vli])==0:
            continue
        for i in vd[vli]:
            if isLinesIntersecting(vert[vli],vert[i],vert[vi1],vert[vi2]): return False
    
    #Now checking possible crossings (intersectiont) with the edges in 'Edges'.
    if len(Edges)!=0:
        for e in Edges:
            if not isInSamePlane([e.v1,e.v2,vert[vi1],vert[vi2]]): continue
            if isLinesIntersecting(e.v1,e.v2,vert[vi1],vert[vi2]): return False
    return True

def isInSamePlane(v):#checks wheather all the given vertices lie on the same plane or not.
    v1=v[0].co
    v2=v[1].co
    v3=v[2].co
    v4=v[3].co
    
    #creating matrix which represents the eq of plane.
    matrixPlane=Mathutils.Matrix([v4.x-v1.x, v4.y-v1.y, v4.z-v1.z],\
                                 [v4.x-v2.x, v4.y-v2.y, v4.z-v2.z],\
                                 [v4.x-v3.x, v4.y-v3.y, v4.z-v3.z])
##    if DEBUG:
##        print '.....matrixPlane dump.....'
##        print matrixPlane
##        print '.....dump complete.....'
    if matrixPlane.determinant()==0: #then the vert.s lie in a plane.
        return True
    else:
        return False

def signOf(no):
    if no<0:
        return 1
    else:
        return 0
    
def isTrigulizable(tvl,vert):
    for v in vert:
        x=v.co.x
        y=v.co.y
        SKIP=False
        for i in range(len(tvl)):
            if (x,y)==(tvl[i].co.x,tvl[i].co.y):
                SKIP=True
                break
        if SKIP: continue
        
        outCount=0
        for i in range(len(tvl)):
            if i==2:
                j=0
            else:
                j=i+1
            if j==2:
                k=0
            else:
                k=j+1
            x1=tvl[i].co.x
            y1=tvl[i].co.y
            
            x2=tvl[j].co.x
            y2=tvl[j].co.y
            
            x3=tvl[k].co.x
            y3=tvl[k].co.y
            
            if (x2-x1)==0:
                if signOf((x1-x3))!=signOf((x1-x)):
                    outCount+=1
                continue
            
            k=(y2-y1)/(x2-x1)
            eq1=y1-y+k*(x-x1)
            eq2=y1-y3+k*(x3-x1)
            if signOf(eq1)!=signOf(eq2):
                outCount+=1
        if outCount==0:
            return False
    return True
    
def bubblesort(l,by,start,end): #bubble sorts the portion of list l starting from 'start' to 'end'(exclusive)
    #according to increasing values of 'by'.
    for i in range(start,end):
        DrawProgressBar(i/end,"Bubble Sorting")
        for j in range(i+1,end):
            if l[i][by]>l[j][by]:
                t=l[i]
                l[i]=l[j]
                l[j]=t
    return l

def vert2face(makeQuads):
    selection = Object.GetSelected()
    if len(selection) == 0:
        error('No object selected')
        return
        
    if len(selection)>1:
        error('Select only one object')
        return
    
    if selection[0].getType() != 'Mesh':
        error('Only mesh are allowed.')
        return
    
    obj=selection[0].getData() #getting the object.
    
    #getting list of all selected vertices.
    vert=[]
    first=True
    for v in obj.verts:
        if first:
            first=False
            minZ=v.co.z
            maxZ=v.co.z
        else:
            if v.co.z<minZ: minZ=v.co.z
            if v.co.z>maxZ: maxZ=v.co.z
        if v.sel:
            vert.append(v)
    
    #getting list of edges, even if none of the vertices of it are selected.
    Edges=[]
    for e in obj.edges:
        v1=e.v1
        v2=e.v2
        if v1.sel and v2.sel: #we don't want the selected edges again in the list of edges to be checked for crossing.
            continue
        v1=v1.co
        v2=v2.co
        if (v1.z<minZ and v2.z<minZ) or (v1.z>maxZ and v2.z>maxZ):
            continue
        Edges.append(e)

    #getting selected faces and the vertices which are not to be connected.
    face=[]
    doNotConnect=[]
    for f in obj.faces:
        selVCount=0
        totVCount=0
        selv=[]
        for v in f.v:
            totVCount+=1
            if v.sel:
                selVCount+=1
                selv.append(v)
        if selVCount==4: face.append(f)
        if totVCount==3 and selVCount==3:
            face.append(f)
            continue
        if selVCount==3 and totVCount==4:
            for i in range(len(selv)):
                for j in range(i+1,len(selv)):
                    if obj.findEdge(selv[i],selv[j]) is None:
                        doNotConnect.append([selv[i],selv[j]])

    #removing selected faces.
    for f in face:
        edge=[]
        for i in range(len(f.v)):
            for j in range(i+1,len(f.v)):
                e=obj.findEdge(f.v[i],f.v[j])
                if e is not None:
                    edge.append(e)
        #now removing the face.
        obj.removeFace(f)
        #recreating removed edges. (Vertices are not automatically deleted. Hence no fuss with that)
        for e in edge:
            obj.addEdge(e.v1,e.v2)
    obj.update()
    
    ##Hence for revision.##
    #obj is the mesh object.
    #vert is the list of selected vertices.
    #doNotConnect is a list of vertices NOT to be connected.
    
    if DEBUG:
        print "==Vertices data dump=="
        i=0
        for v in vert:
            print "vert "+str(i)+" ("+str(v.co.x)+","+str(v.co.y)+") ::-> "+str(v)
            i=i+1
        print("==Dump complete==")
    
    #calculating distances of each vertice with every other.
    stdDev=[]
    for i in range(len(vert)):
        DrawProgressBar(i/len(vert),'Calculating dis. of each vert with every other')
        r=[]
        for j in range(len(vert)):
            if i==j: continue
            dis=calDis(vert[i],vert[j])
            if dis==0:
                error('Maybe faulty mesh. Two vertices in the same location.')
                return
            r.append(dis)
        stdDev.append([calStdDeviation(r),i])
    
    #bubble sorting stdDev according to increasing values of std deviation.
    stdDev=bubblesort(stdDev,0,0,len(stdDev))
    
    if DEBUG:
        print '@@stdDev dump@@'
        for s in stdDev:
            print s
        print '@@Dump complete@@'
    
    #sorting vert according to increasing stdDev.
    tvert=[]
    P=0
    for sd in stdDev:
        tvert.append(vert[sd[1]])
        DrawProgressBar(P/len(stdDev),'Sorting vertices according to stdDev')
        P+=1
    vert=tvert
    tvert=[]#clearing it
    stdVert=[]#clearing it
    
    vd=[] #stores index of all the vertices a particular vertex is connected to.
    #first searching and updating vd of already connected vertices.
    for i in range(len(vert)):
        DrawProgressBar(i/len(vert),'finding already connected verts')
        r=[]
        for j in range(i+1,len(vert)):
            if obj.findEdge(vert[i],vert[j]) is not None:
                r.append(j)
        vd.append(r)
    if DEBUG:
        print '**vd dump (of already connected vertices)**'
        for v in vd:
            print v
        print '**Dump complete**'
    
    #now connecting vertices.
    for i in range(len(vert)):
        DrawProgressBar(i/len(vert),'Connecting verts')
        for j in range(i+1,len(vert)):
            if vd[i].count(j)==0 and isConnectable(vert,vd,doNotConnect,Edges,i,j):
                vd[i].append(j)
    
    if DEBUG:
        print '**vd dump (Final)**'
        for v in vd:
            print v
        print '**Dump complete**'
    
    #making faces (tris). :-)
    vertexList=[]
    if DEBUG: print '000vertexList dump000'
    for vi in range(len(vd)):
        DrawProgressBar(vi/len(vd),'Making faces :) (tris)')
        vil=vd[vi]
        for i in vil:
            for j in vil:
                if i==j: continue
                if vd[i].count(j)!=0: #means vert[i] is connected with vert[j].
                    vertices=[vert[vi],vert[i],vert[j]]
                    if isTrigulizable(vertices,vert):
                        vertexList.append(vertices)
                        if DEBUG: print [vi,i,j]
    if DEBUG: print '000dump complete000'


    ########Part 2. Converting tris to quads.#########
    if makeQuads:
        #scannig for tris with common vertices.
        triPair=[]
        for i in range(len(vertexList)):
            DrawProgressBar(i/len(vertexList),'Scanning for mergeable tris')
            for j in range(i+1,len(vertexList)):
                commonCount=0
                singleVert=[]
                commonVert=[]
                v=[]
                V1=[]
                V1.extend(vertexList[i])
                V2=[]
                V2.extend(vertexList[j])
                for vi in vertexList[i]:
                    for vj in vertexList[j]:
                        if (vi.co.x,vi.co.y)==(vj.co.x,vj.co.y):
                            commonVert.append(vi)
                            V1.remove(vi)
                            V2.remove(vj)
                            commonCount+=1
                            break
                singleVert.extend(V1)
                singleVert.extend(V2)
                v.append(singleVert)
                v.append(commonVert)
                
                if DEBUG:
                    if commonCount!=2: print 'ooo> Tris '+str(i)+' & '+str(j)+' unpaired, since common vertices count!=2'
                if commonCount==2:
                    tv=[]
                    tv.extend(v[0])
                    tv.extend(v[1])
                    if not isInSamePlane(tv): continue #vertices not in same plane hence shouldn't be connected.
                    vec=[]
                    for I in range(len(v)):
                        for iI in range(len(v[I])):
                            v1=v[I][iI]
                            if I==0: J=1
                            else: J=0
                            for v2 in v[J]:
                                ptx=v2.co.x-v1.co.x
                                pty=v2.co.y-v1.co.y
                                vec.append(Mathutils.Vector([ptx,pty]))
                            if iI==0: iJ=1
                            else: iJ=0
                            v2=v[I][iJ]
                            ptx=v2.co.x-v1.co.x
                            pty=v2.co.y-v1.co.y
                            vec.append(Mathutils.Vector([ptx,pty]))
                    
                    SKIP=False
                    ang=[]
                    dis=[]
                    for k in range(0,len(vec),3):
                        angle1=Mathutils.AngleBetweenVecs(vec[k],vec[k+2])
                        angle2=Mathutils.AngleBetweenVecs(vec[k+1],vec[k+2])
                        angle=angle1+angle2
                        if angle>=180: #when ANY of the angles in a quad is 180 or more then it is better to have tris than such a quad.
                            SKIP=True
                            break
                        ang.append(angle)
                        dis.append(vec[k].length);
                    if SKIP:
                        if DEBUG: print 'ooo> Tris '+str(i)+' & '+str(j)+' unpaired, since angle>=180'
                        continue
                    else:
                        triPair.append([i,j,calStdDeviation(ang),calStdDeviation(dis)])
        if DEBUG:
            print '""""triPair dump(unsorted)""""'
            print triPair
            print '""""dump complete""""'
        
        #sorting triPair according to increasing values of angle deviation.
        triPair=bubblesort(triPair,2,0,len(triPair))
        #distance deviation is used for sorting pairs with same angle deviation.
        for i in range(len(triPair)):
            sameCount=0
            for j in range(i+1,len(triPair)):
                if triPair[j][2]!=triPair[i][2]: break
                sameCount+=1
            if sameCount==0: continue
            triPair=bubblesort(triPair,3,i,i+sameCount+1)
            i+=sameCount
        
        #removing all pairs in triPair that have any of their vertices present already in the pairs preceeding it.
        for i in range(len(triPair)):
            if triPair[i]==[]: continue
            for j in range(i+1,len(triPair)):
                if triPair[j]==[]: continue
                if triPair[i][0]==triPair[j][0] or triPair[i][0]==triPair[j][1] or triPair[i][1]==triPair[j][0] or triPair[i][1]==triPair[j][1]:
                    triPair[j]=[] #actually they are not removed but are set to [].
        if DEBUG:
            print
            print '""""triPair dump(final)""""'
            print triPair
            print '""""dump complete""""'
        
        #now making quad faces.
        face=[]
        P=0
        for t in triPair:
            DrawProgressBar(P/len(triPair),'Making quads')
            P+=1
            if t==[]: continue
            v=[]
            v.extend(vertexList[t[0]])
            #searching and appending only the vertices which are not in v.
            for vrt in vertexList[t[1]]:
                present=False
                for vrt1 in vertexList[t[0]]:
                    if (vrt1.co.x,vrt1.co.y)==(vrt.co.x,vrt.co.y):
                        v.remove(vrt1)
                        v.append(vrt1)
                        present=True
                if not present:
                    alone=vrt
            obj.removeEdge(v[1],v[2]) #removing the common edge from the mesh.
            v.insert(2,alone)
            vertexList[t[0]]=[]
            vertexList[t[1]]=[]
            if DEBUG:
                print 'final face vertex list->'+str(v)
            face.append(NMesh.Face(v))

    #now making tris faces.
    if not makeQuads: face=[]
    for t in vertexList:
        if t==[]: continue
        face.append(NMesh.Face(t))
    
    #updating obj.
    for f in face:
        obj.addFace(f)
    
    obj.update()

##calling vert2face##
Window.DrawProgressBar(0.0, 'Vertices to Faces v alpha2 ')
print '========================================'
print 'Vertices to Faces v apha2. Processing...'
if Draw.PupMenu("Make quads?")==-1:
    makeQuads=False
else:
    makeQuads=True
is_editmode = Window.EditMode()
if is_editmode: Window.EditMode(0)
vert2face(makeQuads)
if is_editmode: Window.EditMode(1)
print 'Done!'
print '========================================'
Window.DrawProgressBar(1.0, '')

Hope u enjoy! :smiley:

Hi is anyone listening? :expressionless:

I downloaded your updated version and it works better than shift F. However, it would be even better if it could recognize concave areas and avoid filling them, or maybe group neighboring vertices into regular blocks and fill them that way. For example, I tried it on extruded text with front and back unselected before converting the text to mesh (resulting in hollow mesh, to see if the script could fill it better than the default way). It had trouble filling in O, X, S, T etc. I’m not a coder so I wouldn’t know if it is very hard to determine which faces to fill or determining the outside and inside of an irregular area bounded by vertices… Maybe a challenge for you?

nice man… I’ll have to give it a go later :wink:

I’m sure many people (like me) is listening :wink:
Good work!