Edge fillet and other bmesh tools

Hi zmj100,

looks absolutely great!

Please can you make a little “how to do”.

How can i make before/after in post 3 (or 4)?

How can i make a rounded (filled) plane?
Only with Alt F or is there a “hidden” automatic fill?
etc…

Thanks in advance!

Dito

@ Dito

The scripts here are not finished
To make something like in post 3 or 4 just round corners of edge path using fillet addon.
It does not create all the edges for now.
Extrude that edge path and use blender solidify tool or use split_solidify that i created.
I will try to finish those as soon as i can.

Hi zmj100,
thanks for your answer.
I look forward already to the script!

hi zmj100

thanks but i think that i will wait for the 2.58 version

it is a real torture to go back to 2.49 :wink:



# -*- coding: utf-8 -*-

# ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ***** END GPL LICENCE BLOCK *****

# ------ ------
bl_info = {
    'name': 'fillet',
    'author': '',
    'version': (0, 0, 2),
    'blender': (2, 5, 8),
    'api': 38887,
    'location': '',
    'description': '',
    'warning': '',
    'wiki_url': '',
    'tracker_url': '',
    'category': 'Mesh' }

# ------ ------
import bpy
from bpy.props import FloatProperty, IntProperty, PointerProperty, EnumProperty, BoolProperty
from mathutils import Vector, Matrix
from math import degrees, radians, cos, pi

# ------ ------
def edit_mode_out():      # edit mode out
    bpy.ops.object.mode_set(mode = 'OBJECT')

def edit_mode_in():      # edit mode in
    bpy.ops.object.mode_set(mode = 'EDIT')

def get_adj_v_(me):      # get vert adj to sel vert
    for e in me.edges:
        try:             f_buf.dict_0[e.key[0]].append(e.key[1])
        except KeyError: f_buf.dict_0[e.key[0]] = [e.key[1]]
        try:             f_buf.dict_0[e.key[1]].append(e.key[0])
        except KeyError: f_buf.dict_0[e.key[1]] = [e.key[0]]

# ------ ------
def list_clear_(l):
    l[:] = []
    return l

def f_1(frst, list_):      # frst - firts vert in path, list_ - list of edges

    fi = frst
    tmp = [frst]

    while list_ != []:
        for i in list_:
            if i[0] == fi:
                tmp.append(i[1])
                fi = i[1]
                list_.remove(i)
            elif i[1] == fi:
                tmp.append(i[0])
                fi = i[0]
                list_.remove(i)
    return tmp

# ------ ------
class ff_p_group0(bpy.types.PropertyGroup):

    enum_ = EnumProperty( items =( ('ff_opt0', 'edge', ''),
                                   ('ff_opt1', 'vert', '') ),
                          name = 'test',
                          default = 'ff_opt0' )

# ------ ------
class f_buf():

    me_data = []
    dict_0 = {}

def f_(me, adj, n):
    pass

def f_0(me, n, adj, out, flip):

    list_0 = [ [e.vertices[0], e.vertices[1]] for e in me.edges if e.select ]
    frst = [i for i in list_0[0] if i not in list_0[1]][0]

    list_1 = f_1(frst, list_0)
    list_2 = []
    dict_1 = {}

    i = 1
    p = me.vertices[list_1[i]].co
    p1 = me.vertices[list_1[(i - 1) % n]].co
    p2 = me.vertices[list_1[(i + 1) % n]].co

    vec1 = p - p1
    vec2 = p - p2

    ang = vec1.angle(vec2)

    h = adj * (1 / cos(ang * 0.5))

    p3 = p - (vec1.normalized() * adj)
    p4 = p - (vec2.normalized() * adj)
    rp = p - ((p - ((p3 + p4) * 0.5)).normalized() * h)

    vec3 = rp - p3
    vec4 = rp - p4

    axis = vec1.cross(vec2)

    if out == False:
        if flip == False:
            rot_ang = vec3.angle(vec4)
            for j in range(n + 1):
                new_angle = rot_ang * j / n
                mtrx = Matrix.Rotation(new_angle, 3, axis)
                tmp = p4 - rp
                tmp1 = tmp * mtrx
                tmp2 = tmp1 + rp
                me.vertices.add(1)
                me.vertices[-1].co = tmp2
                me.vertices[-1].select = False
                list_2.append(me.vertices[-1].index)
        
        if flip == True:
            rot_ang = vec1.angle(vec2)
            for j in range(n + 1):
                new_angle = rot_ang * j / n
                mtrx = Matrix.Rotation(new_angle, 3, axis)
                tmp = p3 - p
                tmp1 = tmp * mtrx
                tmp2 = tmp1 + p
                me.vertices.add(1)
                me.vertices[-1].co = tmp2
                me.vertices[-1].select = False
                list_2.append(me.vertices[-1].index)

    elif out == True:
        rot_ang = (2 * pi) - vec1.angle(vec2)
        for j in range(n + 1):
            new_angle = rot_ang * j / n
            mtrx = Matrix.Rotation(new_angle, 3, axis)
            tmp = p4 - p
            tmp1 = tmp * mtrx
            tmp2 = tmp1 + p

            me.vertices.add(1)
            me.vertices[-1].co = tmp2
            me.vertices[-1].select = False
            list_2.append(me.vertices[-1].index)

    n1 = len(list_2)
    for j in range(n1 - 1):
        a = list_2[j]
        b = list_2[(j + 1) % n1]
        me.edges.add(1)
        me.edges[-1].vertices = [a, b]

    me.vertices[list_1[0]].select = False
    me.vertices[list_1[2]].select = False

    if flip == False:
        me.edges.add(1)
        me.edges[-1].vertices = [list_2[-1], list_1[0]]
        me.edges.add(1)
        me.edges[-1].vertices = [list_2[0], list_1[2]]
    elif flip == True:
        me.edges.add(1)
        me.edges[-1].vertices = [list_2[-1], list_1[2]]
        me.edges.add(1)
        me.edges[-1].vertices = [list_2[0], list_1[0]]

# ------ panel 0 ------
class f_p0(bpy.types.Panel):

    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    #bl_idname = 'f_p0_id'
    bl_label = 'Fillet'
    bl_context = 'mesh_edit'

    def draw(self, context):
        layout = self.layout
        layout.prop(context.scene.ff_my_custom_props, 'enum_', text = 'tt', expand = True)
        layout.operator('f.op0_id', text = 'Fillet')

# ------ operator 0 ------
class f_op0(bpy.types.Operator):

    bl_idname = 'f.op0_id'
    bl_label = 'fillet'
    bl_options = {'REGISTER', 'UNDO'}

    adj = FloatProperty( default = 0.08, min = 0.00001, max = 100.0, step = 1, precision = 3 )
    n = IntProperty( name = '', default = 12, min = 3, max = 100, step = 1 )
    out = BoolProperty( name = 'Outside', default = False )
    flip = BoolProperty( name = 'Flip', default = False )

    def draw(self, context):
        layout = self.layout
        
        layout.label('distance')
        layout.prop(self, 'adj')
        layout.label('number of sides')
        layout.prop(self, 'n')
        layout.prop(self, 'out')
        if self.out == False:
            layout.prop(self, 'flip')

    def execute(self, context):
        c_e = context.scene.ff_my_custom_props.enum_
        n = self.n
        adj = self.adj
        out = self.out
        flip = self.flip
        
        edit_mode_out()
        ob_act = context.active_object
        me = ob_act.data
        # -- -- -- --
        f_buf.dict_0.clear()
        get_adj_v_(me)

        f_buf.me_data = me.copy()
        # -- -- -- --
        edit_mode_in()

        
        #bpy.ops.mesh.delete(type = 'VERT')

        edit_mode_out()
        # -- -- -- --
        if c_e == 'ff_opt0':
            f_0(me, n, adj, out, flip)
        else:
            pass
        
        # -- -- -- --
        edit_mode_in()
        bpy.ops.mesh.delete(type = 'VERT')
        bpy.data.meshes.remove(f_buf.me_data)
        return {'FINISHED'}

# ------ ------
class_list = [ f_p0,
               f_op0,
               ff_p_group0 ]

# ------ register ------
def register():
    for c in class_list:
        bpy.utils.register_class(c)

    bpy.types.Scene.ff_my_custom_props = PointerProperty(type = ff_p_group0)

# ------ unregister ------
def unregister():
    for c in class_list:
        bpy.utils.unregister_class(c)

    del bpy.context.scene['ff_my_custom_props']

# ------ ------
if __name__ == "__main__":
    register()



[ATTACH=CONFIG]149799[/ATTACH]

New code.

To use:
Go to edit mode.
Vertex select mode.
Select two adjacent edges.
Click Fillet button and play with the rest of the buttons.

Do not click vert toggle does not work yet.
This is for multiple corners.

Possible results:

If Outside selected and if Flip selected:




Hi, nice script
but with something strange in it: if adjacent edges are selected by the edge-selection-tool at my version it behaves very strange:
part of the mesh is deleted ???

Great ZMJ100!
I will test it now!

This script looks very promising, and - I could be wrong - a bit easier to use than Zeffii one?

@ PKHG

Yes I know about that.
That is one of the bugs that i have to fix.
It works ok in vertex select mode.

Yes (selecting vertices ) is OK… That selecting edges problem is strange … (going in and out of edit mode?, will try later) …

Doesn’t work for me.

Traceback (most recent call last):
File “E:\Blender_YAFARAY\2.58\scripts\addons\fillet.py”, line 248, in execute f_0(me, n, adj, out, flip)
File “E:\Blender_YAFARAY\2.58\scripts\addons\fillet.py”, line 98, in f_0 frst = [i for i in list_0[0] if i not in list_0[1]][0]
File “E:\Blender_YAFARAY\2.58\scripts\addons\fillet.py”, line 98, in frst = [i for i in list_0[0] if i not in list_0[1]][0]
IndexError: list index out of range
location::-1

WinXP Blender Rev. 38842

If the index is out of range you did not select two adjacent edges.
You have to select two adjacent edges or three vertices that belong to that edges.
I have to add error popup to that code.

Hi zmj100,

it works!
Many thanks for your fast feedback.

Dito

Update

To use:
Go to edit mode.
Go vertex select mode.
Select two adjacent edges.
Click Fillet button and play with the options.

I have decided to remove toggle buttons to make gui less confusing.
I have added popup error dialog, and got rid of most of the bugs.
There is two bugs that for now i do not know how to fix.

Addon can not be used in edge select mode because Blender instead of deleting just one corner vertex deletes edges connected to that vertex and in one special case when two adjacent vectors do not have the same direction edges are not being created properly if that happens just click correct edges.

Attachments


Update



# -*- coding: utf-8 -*-

# ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ***** END GPL LICENCE BLOCK *****

# ------ ------
bl_info = {
    'name': 'fillet',
    'author': '',
    'version': (0, 0, 4),
    'blender': (2, 5, 8),
    'api': 38887,
    'location': 'View3D > Tool Shelf',
    'description': '',
    'warning': '',
    'wiki_url': '',
    'tracker_url': '',
    'category': 'Mesh' }

# ------ ------
import bpy
from bpy.props import FloatProperty, IntProperty, BoolProperty
from mathutils import Vector, Matrix
from math import cos, pi
from mathutils.geometry import intersect_line_line

# ------ ------
def edit_mode_out():
    bpy.ops.object.mode_set(mode = 'OBJECT')

def edit_mode_in():
    bpy.ops.object.mode_set(mode = 'EDIT')

def f_1(frst, list_):

    fi = frst
    tmp = [frst]

    while list_ != []:
        for i in list_:
            if i[0] == fi:
                tmp.append(i[1])
                fi = i[1]
                list_.remove(i)
            elif i[1] == fi:
                tmp.append(i[0])
                fi = i[0]
                list_.remove(i)
    return tmp

# ------ ------
class f_buf():
    me_data = []
    msg_type = ''
    msg = ''

def f_(me, list_tmp, n, adj, out, flip, ce):

    list_0 = list_tmp[:]
    frst = [i for i in list_0[0] if i not in list_0[1]][0]
    list_1 = f_1(frst, list_0)

    list_2 = []
    list_3 = []

    i = 1
    p = (me.vertices[list_1[i]].co).copy()
    p1 = (me.vertices[list_1[(i - 1) % n]].co).copy()
    p2 = (me.vertices[list_1[(i + 1) % n]].co).copy()

    vec1 = p - p1
    vec2 = p - p2

    ang = vec1.angle(vec2)

    h = adj * (1 / cos(ang * 0.5))

    p3 = p - (vec1.normalized() * adj)
    p4 = p - (vec2.normalized() * adj)
    rp = p - ((p - ((p3 + p4) * 0.5)).normalized() * h)

    vec3 = rp - p3
    vec4 = rp - p4

    axis = vec1.cross(vec2)

    if out == False:
        if flip == False:
            rot_ang = vec3.angle(vec4)
            for j in range(n + 1):
                new_angle = rot_ang * j / n
                mtrx = Matrix.Rotation(new_angle, 3, axis)
                tmp = p4 - rp
                tmp1 = tmp * mtrx
                tmp2 = tmp1 + rp
                list_2.append(tmp2)

        elif flip == True:
            rot_ang = vec1.angle(vec2)
            for j in range(n + 1):
                new_angle = rot_ang * j / n
                mtrx = Matrix.Rotation(new_angle, 3, axis)
                tmp = p3 - p
                tmp1 = tmp * mtrx
                tmp2 = tmp1 + p
                list_2.append(tmp2)
                
    elif out == True:
        rot_ang = (2 * pi) - vec1.angle(vec2)
        for j in range(n + 1):
            new_angle = rot_ang * j / n
            mtrx = Matrix.Rotation(new_angle, 3, axis)
            tmp = p4 - p
            tmp1 = tmp * mtrx
            tmp2 = tmp1 + p
            list_2.append(tmp2)

    # -- -- -- --
    n1 = len(list_2)
    for j in range(n1):
        me.vertices.add(1)
        me.vertices[-1].co = list_2[j]
        me.vertices[-1].select = False
        list_3.append(me.vertices[-1].index)

    # -- -- -- --
    for k in range(n1 - 1):
        a = list_3[k]
        b = list_3[(k + 1) % n1]
        me.edges.add(1)
        me.edges[-1].vertices = [a, b]

    me.vertices[list_1[0]].select = False
    me.vertices[list_1[2]].select = False

    if flip == True:
        me.edges.add(2)
        me.edges[-1].vertices = [list_3[-1], list_1[2]]
        me.edges[-2].vertices = [list_3[0], list_1[0]]
    else:
        if ce == False:
            me.edges.add(2)
            me.edges[-1].vertices = [list_3[-1], list_1[0]]
            me.edges[-2].vertices = [list_3[0], list_1[2]]

        elif ce == True:
            me.edges.add(2)
            me.edges[-1].vertices = [list_3[-1], list_1[2]]
            me.edges[-2].vertices = [list_3[0], list_1[0]]

    me.update(calc_edges = True)

# ------ ------
class f_msg_popup(bpy.types.Operator, f_buf):

    bl_idname = 'f.msg_id'
    bl_label = ''

    def draw(self, context):
        if self.msg_type == 'Error :':
            self.t = 'ERROR'
        else:
            self.t = 'NONE'
                
        layout = self.layout
        row = layout.split(0.20)
        row.label(self.msg_type, icon = self.t)
        row.label(self.msg)

    def execute(self, context):
        return {'FINISHED'}

    def invoke(self, context, event):
        return context.window_manager.invoke_popup(self)

# ------ panel 0 ------
class f_p0(bpy.types.Panel):

    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    #bl_idname = 'f_p0_id'
    bl_label = 'Fillet'
    bl_context = 'mesh_edit'

    def draw(self, context):
        layout = self.layout
        
        layout.operator('f.op0_id', text = 'Fillet')

# ------ operator 0 ------
class f_op0(bpy.types.Operator):

    bl_idname = 'f.op0_id'
    bl_label = 'fillet'
    bl_options = {'REGISTER', 'UNDO'}

    adj = FloatProperty( default = 0.08, min = 0.00001, max = 100.0, step = 1, precision = 3 )
    n = IntProperty( name = '', default = 4, min = 3, max = 100, step = 1 )
    out = BoolProperty( name = 'Outside',default = False )
    flip = BoolProperty( name = 'Flip',default = False )
    ce = BoolProperty( name = 'Correct edges', default = False )

    def draw(self, context):
        layout = self.layout
        layout.label('Distance:')
        layout.prop(self, 'adj')
        layout.label('Number of sides:')
        layout.prop(self, 'n')
        layout.prop(self, 'out')
        if self.out == False:
            layout.prop(self, 'flip')
        layout.prop(self, 'ce')
    
    def execute(self, context):

        n = self.n
        adj = self.adj
        out = self.out
        flip = self.flip
        ce = self.ce
        
        edit_mode_out()
        ob_act = context.active_object
        me = ob_act.data
        # -- -- -- --
        list_tmp = [ [e.vertices[0], e.vertices[1]] for e in me.edges if e.select ]
        e_mode = [i for i in bpy.context.tool_settings.mesh_select_mode]
        
        if len(list_tmp) != 2:
            f_buf.msg_type = 'Error :'
            f_buf.msg = 'Only two adjacent edges must be selected.'
            bpy.ops.f.msg_id('INVOKE_DEFAULT')
            edit_mode_in()
            return 'CANCELLED'
        elif e_mode[1] == True:
            f_buf.msg_type = 'Error :'
            f_buf.msg = 'Switch to vertex select mode.'
            bpy.ops.f.msg_id('INVOKE_DEFAULT')
            edit_mode_in()
            return 'CANCELLED'
        else:
            f_(me, list_tmp, n, adj, out, flip, ce)
            del list_tmp
        # -- -- -- --
        edit_mode_in()
        bpy.ops.mesh.delete(type = 'VERT')
        return {'FINISHED'}

# ------ ------
class_list = [ f_p0,
               f_op0,
               f_msg_popup ]

# ------ register ------
def register():
    for c in class_list:
        bpy.utils.register_class(c)

# ------ unregister ------
def unregister():
    for c in class_list:
        bpy.utils.unregister_class(c)

# ------ ------
if __name__ == "__main__":
    register()




To use:
Go to edit mode.
Go vertex select mode.
Select two adjacent edges.
Click Fillet button and play with the options.

I have decided to remove toggle buttons to make gui less confusing.
I have added popup error dialog, and got rid of most of the bugs.
There is two bugs that for now i do not know how to fix.

Addon can not be used in edge select mode because Blender instead of deleting just one corner vertex deletes edges connected to that vertex and in one special case when two adjacent vectors do not have the same direction edges are not being created properly if that happens just click correct edges.

If anybody wants to try to fix those bugs be my guest.
For now i am very happy with what the script does.

Another great reason to give better, more descriptive, names to your variables/functions/operators. debugging!

Update

Addon now works in vertex select mode and edge select mode.
If you are switching from Flip to Outside unselect Flip first or it will create bad edges.



# -*- coding: utf-8 -*-

# ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ***** END GPL LICENCE BLOCK *****

# ------ ------
bl_info = {
    'name': 'fillet',
    'author': '',
    'version': (0, 0, 6),
    'blender': (2, 5, 8),
    'api': 38887,
    'location': 'View3D > Tool Shelf',
    'description': '',
    'warning': '',
    'wiki_url': '',
    'tracker_url': '',
    'category': 'Mesh' }

# ------ ------
import bpy
from bpy.props import FloatProperty, IntProperty, BoolProperty
from mathutils import Vector, Matrix
from math import cos, pi
from mathutils.geometry import intersect_line_line

# ------ ------
def edit_mode_out():
    bpy.ops.object.mode_set(mode = 'OBJECT')

def edit_mode_in():
    bpy.ops.object.mode_set(mode = 'EDIT')

def f_1(frst, list_):

    fi = frst
    tmp = [frst]

    while list_ != []:
        for i in list_:
            if i[0] == fi:
                tmp.append(i[1])
                fi = i[1]
                list_.remove(i)
            elif i[1] == fi:
                tmp.append(i[0])
                fi = i[0]
                list_.remove(i)
    return tmp

# ------ ------
class f_buf():
    me_data = []
    msg_type = ''
    msg = ''

def f_(me, list_tmp, n, adj, out, flip, ce):

    list_0 = list_tmp[:]
    frst = [i for i in list_0[0] if i not in list_0[1]][0]
    list_1 = f_1(frst, list_0)
    e_mode = [i for i in bpy.context.tool_settings.mesh_select_mode]
    
    list_2 = []
    list_3 = []

    i = 1
    p = (me.vertices[list_1[i]].co).copy()
    p1 = (me.vertices[list_1[(i - 1) % n]].co).copy()
    p2 = (me.vertices[list_1[(i + 1) % n]].co).copy()

    vec1 = p - p1
    vec2 = p - p2

    ang = vec1.angle(vec2)

    h = adj * (1 / cos(ang * 0.5))

    p3 = p - (vec1.normalized() * adj)
    p4 = p - (vec2.normalized() * adj)
    rp = p - ((p - ((p3 + p4) * 0.5)).normalized() * h)

    vec3 = rp - p3
    vec4 = rp - p4

    axis = vec1.cross(vec2)

    if out == False:
        if flip == False:
            rot_ang = vec3.angle(vec4)
            for j in range(n + 1):
                new_angle = rot_ang * j / n
                mtrx = Matrix.Rotation(new_angle, 3, axis)
                tmp = p4 - rp
                tmp1 = tmp * mtrx
                tmp2 = tmp1 + rp
                list_2.append(tmp2)

        elif flip == True:
            rot_ang = vec1.angle(vec2)
            for j in range(n + 1):
                new_angle = rot_ang * j / n
                mtrx = Matrix.Rotation(new_angle, 3, axis)
                tmp = p3 - p
                tmp1 = tmp * mtrx
                tmp2 = tmp1 + p
                list_2.append(tmp2)
                
    elif out == True:
        rot_ang = (2 * pi) - vec1.angle(vec2)
        for j in range(n + 1):
            new_angle = rot_ang * j / n
            mtrx = Matrix.Rotation(new_angle, 3, axis)
            tmp = p4 - p
            tmp1 = tmp * mtrx
            tmp2 = tmp1 + p
            list_2.append(tmp2)

    # -- -- -- --
    n1 = len(list_2)
    for j in range(n1):
        me.vertices.add(1)
        me.vertices[-1].co = list_2[j]
        me.vertices[-1].select = False
        list_3.append(me.vertices[-1].index)

    # -- -- -- --
    for k in range(n1 - 1):
        a = list_3[k]
        b = list_3[(k + 1) % n1]
        me.edges.add(1)
        me.edges[-1].vertices = [a, b]


    me.vertices[list_1[0]].select = False
    me.vertices[list_1[2]].select = False

    if flip == True:
        me.edges.add(2)
        me.edges[-1].vertices = [list_3[-1], list_1[2]]
        me.edges[-2].vertices = [list_3[0], list_1[0]]

    else:
        if ce == False:
            me.edges.add(2)
            me.edges[-1].vertices = [list_3[-1], list_1[0]]
            me.edges[-2].vertices = [list_3[0], list_1[2]]
        elif ce == True:
            me.edges.add(2)
            me.edges[-1].vertices = [list_3[-1], list_1[2]]
            me.edges[-2].vertices = [list_3[0], list_1[0]]

    # -- -- -- --
    if e_mode[1] == True:
        for e in me.edges:
            if e.select:
                e.select = False

        tmp = (me.vertices[list_1[1]].co).copy()
        me.vertices.add(1)
        me.vertices[-1].co = tmp
        me.edges.add(1)
        me.edges[-1].vertices = [me.vertices[-1].index, list_1[1]]
    # -- -- -- --
    
    me.update(calc_edges = True)

# ------ ------
class f_msg_popup(bpy.types.Operator, f_buf):

    bl_idname = 'f.msg_id'
    bl_label = ''

    def draw(self, context):
        if self.msg_type == 'Error :':
            self.t = 'ERROR'
        else:
            self.t = 'NONE'
                
        layout = self.layout
        row = layout.split(0.20)
        row.label(self.msg_type, icon = self.t)
        row.label(self.msg)

    def execute(self, context):
        return {'FINISHED'}

    def invoke(self, context, event):
        return context.window_manager.invoke_popup(self)

# ------ panel 0 ------
class f_p0(bpy.types.Panel):

    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    #bl_idname = 'f_p0_id'
    bl_label = 'Fillet'
    bl_context = 'mesh_edit'

    def draw(self, context):
        layout = self.layout
        layout.operator('f.op0_id', text = 'Fillet')

# ------ operator 0 ------
class f_op0(bpy.types.Operator):

    bl_idname = 'f.op0_id'
    bl_label = 'fillet'
    bl_options = {'REGISTER', 'UNDO'}

    adj = FloatProperty( default = 0.08, min = 0.00001, max = 100.0, step = 1, precision = 3 )
    n = IntProperty( name = '', default = 4, min = 3, max = 100, step = 1 )
    out = BoolProperty( name = 'Outside',default = False )
    flip = BoolProperty( name = 'Flip',default = False )
    ce = BoolProperty( name = 'Correct edges',default = False )

    def draw(self, context):
        layout = self.layout
        layout.label('Distance:')
        layout.prop(self, 'adj')
        layout.label('Number of sides:')
        layout.prop(self, 'n')
        layout.prop(self, 'out')
        if self.out == False:
            layout.prop(self, 'flip')
        layout.prop(self, 'ce')
    
    def execute(self, context):

        n = self.n
        adj = self.adj
        out = self.out
        flip = self.flip
        ce = self.ce
        
        edit_mode_out()
        ob_act = context.active_object
        me = ob_act.data
        # -- -- -- --
        list_tmp = [ [e.vertices[0], e.vertices[1]] for e in me.edges if e.select ]
        e_mode = [i for i in bpy.context.tool_settings.mesh_select_mode]
        
        if len(list_tmp) != 2:
            f_buf.msg_type = 'Error :'
            f_buf.msg = 'Only two adjacent edges must be selected.'
            bpy.ops.f.msg_id('INVOKE_DEFAULT')
            edit_mode_in()
            return 'CANCELLED'
        else:
            f_(me, list_tmp, n, adj, out, flip, ce)
            del list_tmp
        # -- -- -- --
        edit_mode_in()
        bpy.ops.mesh.delete(type = 'VERT')
        return {'FINISHED'}

# ------ ------
class_list = [ f_op0, f_msg_popup, f_p0 ]

# ------ register ------
def register():
    for c in class_list:
        bpy.utils.register_class(c)

# ------ unregister ------
def unregister():
    for c in class_list:
        bpy.utils.unregister_class(c)

# ------ ------
if __name__ == "__main__":
    register()




thanks zmj - nice script - i can see it becoming very useful