Cover a contour (relaces SHIFT+F in Edit mode)

Here is a script which covers a contour with faces just like pressing SHIFT+F in Edit mode.

BEFORE

http://s2.orbitfiles.com/4638195588.jpg?link=4638195588&sid=6117bcf7c7bd83ba41734a4dc72a1ba4http://www.geocities.com/elonsie/Blender/Scripts/Cover_contour/Contour_1.jpg

AFTER

http://s2.orbitfiles.com/4638196714.jpg?link=4638196714&sid=6117bcf7c7bd83ba41734a4dc72a1ba4http://www.geocities.com/elonsie/Blender/Scripts/Cover_contour/Contour_2.jpg

By using SHIFT+F in Edit mode the result is:

http://s2.orbitfiles.com/4638197771.jpg?link=4638197771&sid=6117bcf7c7bd83ba41734a4dc72a1ba4http://www.geocities.com/elonsie/Blender/Scripts/Cover_contour/Contour_3.jpg

Sooo… the above solution is more optimal as it results in triangles which are NOT that flat. SHIFT+F leads to obtaining triangles with angle at top vertex > 170 degress in some cases as soon as such a triangle is possible.

Now let’s check what if vertex 28 is “not visible” from vertex 0:

http://s2.orbitfiles.com/4638198628.jpg?link=4638198628&sid=6117bcf7c7bd83ba41734a4dc72a1ba4http://www.geocities.com/elonsie/Blender/Scripts/Cover_contour/Contour_4.jpg

Yay! --> the script finds its way to connect correctly contour verts & produce covering faces inside in a very acceptable manner! :wink:

The script proposed works with flat contours (all verts lie in one plane). Current script checks if the contour is closed ONLY. If you’re not sure wheater your contour is flat, you should check this by using the function isFlatContour(me,threshold) --> NOT published here. Or equivalent function…

Regards,

Let me clarify that in the title I meant that presented script replaces SHIFT+F click in edit mode but this forum does not allow making changes in the title even when you try to correct typos :eek:

Well it appears that there are some bugs and issues to improve:

  1. Should be made to work with ALL right-handed triples. Since the cycle starts when the first left-handed triple is found, if there is NO left-handed triple => the script will NOT cover the contour. It is the situation with standard Blender circle having 7, 8, 16, etc. vertices:

BEFORE

http://www.geocities.com/elonsie/Blender/Scripts/Cover_contour/Circle_7_1.jpg

AFTER rotation of the circle at 180degrees on Y and application of the script (now working pretty fine with ALL left-handed triples):

http://www.geocities.com/elonsie/Blender/Scripts/Cover_contour/Circle_7_2.jpg

Rotation on 180 degrees “changes” polarity of ALL triples… Of course, some changes are needed in the script, not that the user is to rotate his/her object… :wink:

  1. Should be made to run successfully starting from Edit mode - now only working correctly starting from Object mode

  2. Should be made to work with non-flat 2D contours (optional).

Sooo… look here for updates! :wink:

would it be possibel to indicate on the console the numbers of vertices done
it’s just a statistic but and interesting data!

now can you re explain how you made it work cause i tried to rotate mny circle and it did not work again

don’t know what to do unless it is a bug to be corrected in futur!

and by the way is there a way to indicate some how all the vertex number in the mesh ?
i’v been looking for something like that for a while

thanks

I developed the script above while working on another task and about the same time I saw another script (a part of it) doing EXACTLY what SHIFT+F does in Edit mode… It is quite elegant and fast… :yes:

Here it is:

from Blender import *
import bpy

editmode = Window.EditMode()
scn = bpy.data.scenes.active
ob = scn.objects.active
me = ob.getData(mesh=1)
if editmode:
  Window.EditMode(0)    
Mesh.Mode(1)
me.fill()
if editmode:
  Window.EditMode(1)

It is completely nice but it has the deficiencies of the SHIFT+F in Edit mode (naturally):

  1. Always produces “possible” triangles, i.e. including very wide and with a big angle at top vertex (close to 180);
  2. Does NOT work with “bumpy” or what-so-ever non-flat contour while my code can be modified to cope with such situations :wink:

Regards,

how can i make it work with the simple circle and how if possible!

mind you i’d like to see the same but doing a max of quads ona circle shape
easier to work than tri’s adn can use with surbsurf too

Thanks

Ricky, apply the last script (the shortest one) to a 7-vert circle… then apply “Join triangles” => you’ll get 2 nice quads + 1 triangle (unavoidable in a polygon with 7 verts) :wink:

Regards,

Hi Abidos, could you upload the script but modified so that i supply the polyline=[v1,v2,…] and your script fills that polyline?

You don’t even have to check if it is planar or closed

It is for the mesh optimiser

Well, here is the code modified as per your request…

from Blender import *
import bpy

##############################################
#                                            #
#    * * *    Covering a contour    * * *    #
#     (Replaces SHIFT+FKEY in Edit mode)     #
#                                            #
#   Written by Emil Lozanov, a.k.a. Abidos   #
#                                            #
#         version 1.0.1 - 20.08.2009         #
#                                            #
##############################################
    
def Cover_contour():
    sce = Scene.GetCurrent()
    ob = Object.GetSelected()[0]
    oName = ob.name
    me = ob.getData(mesh=1)
    threshold = 0.00001
    verts = Make_verts(me)
    Perform_the_covering(me,verts,threshold)
    
#######  End of Cover_contour()  ###################################

def Make_verts(me):
    lst = [0, 19, 9, 18, 4, 16, 8, 17, 1, 29, 14, 28, 7, 30, 15, 31, 3, 27, 13, 26, 6, 24, 12, 25, 2, 23, 11, 22, 5, 20, 10, 21]
    verts = []
    for vi in lst:
        verts.append(me.verts[vi])
    return verts

def Perform_the_covering(me,verts,threshold):
    flag = True  # means that the contour is closed
    lst_row = []  # proc needs a row of indeces so I will take them from verts...
    for v in verts:
        lst_row.append(v.index)
    newFaces = []
    lst_row_ALL = lst_row[:]
    while flag and (len(lst_row) > 2):
        i = 1
        areThereLeftTriples = False
        while flag and (len(lst_row) > 2):
            vi1 = lst_row[i-1]
            vi = lst_row[i]
            vi2 = lst_row[i+1]
            v1 = me.verts[vi1].co
            v = me.verts[vi].co
            v2 = me.verts[vi2].co
            isLeftTriple = Geometry.PointInTriangle2D(v1,v1,v,v2)
            if isLeftTriple:
                areThereLeftTriples = True
                fl_NoIntersections = NoIntersections(me,lst_row_ALL,vi1,vi2,threshold)
                if fl_NoIntersections:
                    elem = lst_row[i]
                    lst_row.remove(elem)
                    newFaces.append((vi1,vi,vi2))
                else:
                    i += 1
            else:
                i += 1
            flag = (i < (len(lst_row)-1))
        flag = areThereLeftTriples
    me.faces.extend(newFaces)
    Redraw()
    
def NoIntersections(me,lst_row_original,vi1,vi2,threshold):
    lst_row = lst_row_original[:]
    lst_row.append(lst_row[0])  # to close the chain
    v1 = me.verts[vi1].co
    v2 = me.verts[vi2].co
    for i in range(1,len(lst_row)):
        vi3 = lst_row[i-1]
        vi4 = lst_row[i]
        if not ((vi1 in [vi3,vi4]) or (vi2 in [vi3,vi4])):
            v3 = me.verts[vi3].co
            v4 = me.verts[vi4].co
            flag,x,y = SectionsIntersect2D(v1,v2,v3,v4,threshold)
            if flag:
                return False
    return True  # => NO intersections with contour edges...

def Get_LineEqCoefs2D_gen(v1,v2):
    a = (v2.y-v1.y)
    b = (v2.x-v1.x)
    c = a*v1.x-b*v1.y
    return a,b,c

def Get_LinesIntersect2D_onGenEq(lst1,lst2,threshold):
    a1 = lst1[0]
    b1 = lst1[1]
    c1 = lst1[2]
    a2 = lst2[0]
    b2 = lst2[1]
    c2 = lst2[2]
    if abs(a2*b1-a1*b2) <= threshold:
        return None,None
    else:
        y = (a1*c2-a2*c1)/(a2*b1-a1*b2)
        if abs(a1) <= threshold:
            if abs(a2) <= threshold:
                return None,y
            else:
                x = (b2*y+c2)/a2
                return x,y
        else:
            x = (b1*y+c1)/a1
            return x,y

def SectionsIntersect2D(v1,v2,v3,v4,threshold):
    a,b,c = Get_LineEqCoefs2D_gen(v1,v2)
    lst1 = [a,b,c]
    a,b,c = Get_LineEqCoefs2D_gen(v3,v4)
    lst2 = [a,b,c]
    x,y = Get_LinesIntersect2D_onGenEq(lst1,lst2,threshold)
    if (x == None) or (y == None):
        return False,x,y
    else:
        vIntersect = Mathutils.Vector(x,y,0)  # z is NOT taken into account
        flag = SectionsIntersect2D_p(vIntersect,v1,v2,v3,v4,threshold)
        return flag,x,y

def SectionsIntersect2D_p(vIntersect,v1,v2,v3,v4,threshold):
    vec1 = GetVector_2p_3D(v1,vIntersect)
    vec2 = GetVector_2p_3D(v2,vIntersect)
    flag = isSameDir(vec1,vec2,threshold)
    if not flag:  # intersection is between v1,v2
        vec1 = GetVector_2p_3D(v3,vIntersect)
        vec2 = GetVector_2p_3D(v4,vIntersect)
        flag = isSameDir(vec1,vec2,threshold)
    return (not flag)

def GetVector_2p_3D(v1,v2):
    return Mathutils.Vector(v2[0]-v1[0],v2[1]-v1[1],v2[2]-v1[2])
    
def isSameDir(vec1,vec2,threshold):
    flag = True
    for i in xrange(3):
        flag = flag and isSameSign(vec1[i],vec2[i],threshold)
    return flag
        
def isSameSign(a,b,threshold):
    return (((a>0)and(b>0)) or ((a<0)and(b<0)) or ((abs(a)<=threshold)and(abs(b)<=threshold)))

def Make_viv(me):
    viv = {}
    for edge in me.edges:
        v1 = edge.v1.index
        v2 = edge.v2.index
        try: viv[v1].append(v2)
        except KeyError: viv[v1]=[v2]
        try: viv[v2].append(v1)
        except KeyError: viv[v2] = [v1]
    return viv

def Print_title():
    ver = "1.0.1"
    dt = "20.AUG.2009"
    Prt_title(ver,dt)

def Prt_title(ver,dt):
    print
    print "##############################################"
    print "#                                            #"
    print "#    * * *    Covering a contour    * * *    #"
    print "#     (Replaces SHIFT+FKEY in Edit mode)     #"
    print "#                                            #"
    print "#   Written by Emil Lozanov, a.k.a. Abidos   #"
    print "#                                            #"
    st = "#        version "+str(ver)+" - "+str(dt)+"         #"
    print st
    print "#                                            #"
    print "##############################################"
    print

def main():
    Print_title()
    Cover_contour()
    
if __name__ == "__main__":
    main()

You need to replace proc Make_verts(me) with your own one that supplies verts in the order they are in the contour.

Regards,

Thanks Abidos :wink:

I’m stuck again at the other thread…

ok i downloaded the latest version at top of thread frist post

and triedt it again with circle 7 segments and it did not work

so i guess your still working on it !

Thanks