----------

Could use some help with creating side faces of triangles.

why not use solidify modifier?

@ zeffii

Its not about using it. I know i could use solidify modifier.

@ zeffii

Its about learning something new.
I have already created four other addons using that code.

about faces/vertices/edges removing, do you find a way through bpy.data ?

@ littleneo

Link



import bpy

ob_act = bpy.context.active_object

for ob in bpy.data.objects:
    print(ob)
    
#bpy.data.objects.remove(ob_act)

# it is possible to remove ob_act if you remove users

'''
if "Cube" in bpy.data.meshes:
    mesh = bpy.data.meshes["Cube"]
    print("removing mesh", mesh)
    bpy.data.meshes.remove(mesh)
'''

print (bpy.data.objects)

# prints ( bpy_collection[3], BlendDataObjects )

me = ob_act.data
print(me)

print(me.faces)

# prints ( bpy_collection[6], MeshFaces )

# me.faces is a collection just like BlendDataObjects but remove() function does not work
# I have been trying to figure it out but there is not that many pages about collections
# there should be something like these me.faces.remove(me.faces[0]) to remove face data



maybe someone else knows how to do that or if it is even possible but people are not that eager to help.

Everything works now.
Used wrong function to create sides of triangles, those are quads not tris.

To use
Go to edit mode.
Select faces.
Click ‘Test’ button.




v normal added

It would be VERY interesting if your script had also the inverse function for faces generation I think.
I mean to generate faces where there is none at the moment, and leave it empty where there’s faces.
(mmm easier to do with quads I suppose)

Just trying to figure out what it is good for.


@ littleneo

Good idea.
I will think about it, but i am not sure how to do that.

Update
New feature random distance



New version

Corrected calculation of thickness of the faces when using v normals.
Distance slider now moves faces differently.
Corrected creation of side faces.
Added random when using v normals.

To do
Correct calculation of normals in some cases.
Can not recalculate normals to be on outside



I think i just created new solidify tool and i was just trying to learn how to add faces.



More pictures


Attachments


Small update

Added labels to sliders

Not an update

i’m not able to run the code at the moment, but that looks like an off-by-one bug, get yourself the addon called ‘index visualiser’ (search these forums… or go to the scripts section on blender.org). index visualizer displays the indices of verts/edges/faces, you’ll be able to see if there is a vertex created where you expect or not


n = len(list_1)
if n == 3:
    add_tri(me_o, list_2, 1)
    add_tri(me_o, list_1, 1)
    for i in range(n):
        add_quad(me_o, [ list_1[i], list_1[(i + 1) % n], list_2[(i + 1) % n], list_2[i] ], 1)
else:
    add_quad(me_o, list_2, 1)
    add_quad(me_o, list_1, 1)
    for i in range(n):
        add_quad(me_o, [ list_1[i], list_1[(i + 1) % n], list_2[(i + 1) % n], list_2[i] ], 1)

or, at that level of indentation consider a small change in style.


if n == 3:
    add_tri(me_o, list_2, 1)
    add_tri(me_o, list_1, 1)
else:
    add_quad(me_o, list_2, 1)
    add_quad(me_o, list_1, 1)

for i in range(n):
    modval = (i + 1) % n
    param_2 = [ list_1[i], list_1[modval], list_2[modval], list_2[i] ]
    add_quad(me_o, param_2, 1)

i’m aware this stuff was commented out…

interesting…


>>> bpy.context.active_object.data.faces[0].vertices[0]
1
>>> bpy.context.active_object.data.faces[0].vertices[1]
3
>>> bpy.context.active_object.data.faces[0].vertices[2]
5
>>> bpy.context.active_object.data.faces[0].vertices[3]
7

>>> bpy.context.active_object.data.faces[1].vertices[0]
6

>>> bpy.context.active_object.data.faces[1].vertices[1]
4

>>> bpy.context.active_object.data.faces[1].vertices[2]
2

>>> bpy.context.active_object.data.faces[1].vertices[3]
Traceback (most recent call last):
  File "<blender_console>", line 1, in <module>
IndexError: bpy_prop_array[index]: index 3 out of range

>>> 

i’m thinking with an empty mesh, the first vertex in a mesh might (for some reason) have to be 0. ( but you have list_2 = [6,4,2,0])


            add_quad(me_o, list_1, 1)      # out
            deque_list = collections.deque(list_2)
            deque_list.rotate(1)
            list_2 = list(deque_list)            
            add_quad(me_o, list_2, 1)      # in

so… with little modification (including to add_quad)

poke around with this ( seems to work ), you might want to do a check on your very first face creation and rotate until the first element is 0.


# -*- 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': 'split_solidify',
    'author': '',
    'version': (0, 0, 1),
    'blender': (2, 5, 8),
    'api': 38045,
    'location': 'View3D > Tool Shelf',
    'description': '',
    'warning': '',
    'wiki_url': '',
    'tracker_url': '',
    'category': 'Mesh' }

# ------ ------
import bpy
import random
from bpy.props import FloatProperty, EnumProperty, PointerProperty, BoolProperty, IntProperty
from math import cos
import collections

# ------ ------
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 add_quad(msh, lst, n):      # lst - list of face indexes, must be 4    n - number of faces
    msh.faces.add(n)
    msh.faces[-1].vertices_raw = lst
    #msh.update(calc_edges = True)

def add_tri(msh, lst, n):      # lst - list of face indexes, must be 3    n - number of faces
    msh.faces.add(n)
    msh.faces[-1].vertices = lst
    #msh.update(calc_edges = True)

# ------ ------
class t_buf():
    me_data = []

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

    enum_ = EnumProperty( items =( ('opt0', 'f normal', ''),
                                   ('opt1', 'v normal', '') ),

                          name = 'test',
                          default = 'opt0' )

    bool_ = BoolProperty( name = 'Delete original face',
                          default = True )

    bool_1 = BoolProperty( name = 'Random',
                          default = False )

'''
# ------ ------
def f_(me_o, opp, th, context, rnd):

    c_e = context.scene.t_my_custom_props.enum_
    c_ran = context.scene.t_my_custom_props.bool_1

    me = t_buf.me_data
    
    list_0 = [f for f in me.faces if f.select]
    dict_1 = {}
    
    for f in list_0:
        list_1 = []
        list_2 = []
        if c_ran == True:
            d = rnd * random.randrange( 0, 10 )
        else:
               d = opp
        for vi in f.vertices:
            v = me.vertices[vi]
            f_no = f.normal
            v_no = v.normal
            v.select = False
            tmp = [0, 0, 0]
            tmp1 = [0, 0, 0]
            for i in range(3):
                if c_e == 'opt0':
                    tmp1[i] = v.co[i] + (d * f.normal[i])
                    tmp[i] = v.co[i] + ( (d - th) * f.normal[i])
                elif c_e == 'opt1':
                    angle_ = v_no.angle(f_no)
                    h = th / cos(angle_)      # corrected thickness calculation
                    tmp[i] = v.co[i] + (d * f.normal[i])
                    tmp1[i] = tmp[i] + (-h * v.normal[i])

            me_o.vertices.add(2)
            me_o.vertices[-2].co = tuple(tmp1)
            me_o.vertices[-1].co = tuple(tmp)

            list_1.append(me_o.vertices[-2].index)
            list_2.append(me_o.vertices[-1].index)

        n = len(list_1)
        if n == 3:
            add_tri(me_o, list_2, 1)
            add_tri(me_o, list_1, 1)
            for i in range(n):
                add_quad(me_o, [ list_1[i], list_1[(i + 1) % n], list_2[(i + 1) % n], list_2[i] ], 1)
        else:
            add_quad(me_o, list_2, 1)
            add_quad(me_o, list_1, 1)
            for i in range(n):
                add_quad(me_o, [ list_1[i], list_1[(i + 1) % n], list_2[(i + 1) % n], list_2[i] ], 1)

        me_o.update(calc_edges = True)
'''

# ------ ------
def f_(me_o, opp, th, context, rnd):

    c_e = context.scene.t_my_custom_props.enum_
    c_ran = context.scene.t_my_custom_props.bool_1

    me = t_buf.me_data
    list_0 = [f for f in me.faces if f.select]

    # iteration = 0
    for f in list_0:
        
        # if iteration == 1: break
        list_1 = []
        list_2 = []

        if c_ran == True:
            d = rnd * random.randrange(0, 10)
        else:
            d = opp

        for vi in f.vertices:
            v = me.vertices[vi]
            f_no = f.normal      # f normal
            v_no = v.normal      # v normal

            tmp = [0, 0, 0]
            tmp1 = [0, 0, 0]

            for i in range(3):
                
                if c_e == 'opt0':
                    tmp[i] = v.co[i] + (d * f_no[i])      # out
                    tmp1[i] = v.co[i] + ((d - th) * f_no[i])      # in

                    #tmp1[i] = v.co[i] + (d * f.normal[i])
                    #tmp[i] = v.co[i] + ( (d - th) * f.normal[i])
                
                elif c_e == 'opt1':
                    #angle_ = v_no.angle(f_no)
                    #h = th / cos(angle_)      # corrected thickness calculation
                    #tmp[i] = v.co[i] + (d * f.normal[i])
                    #tmp1[i] = tmp[i] + (-h * v.normal[i])
                    pass

            me_o.vertices.add(2)
            me_o.vertices[-1].co = tuple(tmp)      # out
            me_o.vertices[-2].co = tuple(tmp1)      # in
            
            vert_1 = me_o.vertices[-1]
            vert_2 = me_o.vertices[-2]
            print('-1 out  ', vert_1.index, vert_1.co)
            print('-2 in   ', vert_2.index, vert_2.co)
            
            list_1.append(me_o.vertices[-1].index)      # out
            list_2.append(me_o.vertices[-2].index)      # in


        list_2.reverse()      # < flip normal

        n = len(list_1)
        if n == 3:
            add_tri(me_o, list_1, 1)      # out
            add_tri(me_o, list_2, 1)      # in
        else:
            add_quad(me_o, list_1, 1)      # out
            deque_list = collections.deque(list_2)
            deque_list.rotate(1)
            list_2 = list(deque_list)            
            add_quad(me_o, list_2, 1)      # in

        #iteration += 1
        me_o.update(calc_edges = True)            



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

    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    #bl_idname = 't_p0_id'
    bl_label = 'Split solidify'
    bl_context = 'mesh_edit'

    def draw(self, context):
        layout = self.layout
        layout.prop(context.scene.t_my_custom_props, 'enum_', expand = True)
        layout.prop(context.scene.t_my_custom_props, 'bool_')
        layout.prop(context.scene.t_my_custom_props, 'bool_1')
        layout.operator('t.op0_id', text = 'Split solidify')

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

    bl_idname = 't.op0_id'
    bl_label = 'Split solidify'
    bl_options = {'REGISTER', 'UNDO'}

    opp = FloatProperty( default = 0.4, min = -100.0, max = 100.0, step = 10, precision = 3 )
    th = FloatProperty( default = 0.04, min = -100.0, max = 100.0, step = 1, precision = 3 )
    rnd = FloatProperty( default = 0.06, min = -10.0, max = 10.0, step = 1, precision = 3 )

    def draw(self, context):
        c_ran = context.scene.t_my_custom_props.bool_1
        layout = self.layout
        
        if c_ran == False:
            layout.label('Distance')
            layout.prop(self, 'opp')
        else:
            layout.label('Random val.')
            layout.prop(self, 'rnd')
        
        layout.label('Thickness')
        layout.prop(self, 'th')

    def execute(self, context):
        c_b = context.scene.t_my_custom_props.bool_

        opp = self.opp
        th = self.th
        rnd = self.rnd
        
        edit_mode_out()
        # -- -- -- --
        ob_act = context.active_object
        me_o = ob_act.data
        t_buf.me_data = me_o.copy()
        # -- -- -- --
        edit_mode_in()
        if c_b == True:
            bpy.ops.mesh.delete(type = 'FACE')
        else:
            pass
        edit_mode_out()
        # -- -- -- --
        f_(me_o, opp, th, context, rnd)
        # -- -- -- --
        edit_mode_in()
        #bpy.ops.mesh.normals_make_consistent(inside = False)
        bpy.data.meshes.remove(t_buf.me_data)
        
        return {'FINISHED'}

# ------ classes to register ------
class_list = [ t_p0,
               t_op0,
               t_p_group0 ]

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

    bpy.types.Scene.t_my_custom_props = PointerProperty(type = t_p_group0)

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

    del bpy.context.scene['t_my_custom_props']

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