Skip to content
Snippets Groups Projects
add_mesh_honeycomb.py 10.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • # GPL # "author": "Kayo Phoenix"
    
    
    from math import (
            pi, sin,
            cos,
            )
    
    from bpy.props import (
            IntProperty,
            BoolProperty,
            BoolVectorProperty,
            FloatProperty,
            FloatVectorProperty,
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    class honeycomb_geometry():
        def __init__(self, rows, cols, D, E):
            self.rows = rows
            self.cols = cols
            self.D = D
            self.E = E
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            self.hE = 0.5 * self.E
            self.R = 0.5 * self.D
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            self.a = sin(pi / 3)
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            self.d = self.a * self.D
            self.hd = 0.5 * self.d
            self.e = self.hE / self.a
            self.he = 0.5 * self.e
            self.r = self.R - self.e
            self.hr = 0.5 * self.r
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            self.H = self.R * (1.5 * self.rows + 0.5) + self.e
            if self.rows > 1:
                self.W = self.d * (self.cols + 0.5) + self.E
            else:
                self.W = self.d * self.cols + self.E
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            self.hH = 0.5 * self.H
            self.hW = 0.5 * self.W
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            self.sy = -self.hH + self.he + self.R
            self.sx = -self.hW + self.hE + self.hd
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            self.gx = self.hd
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            self.dy = 1.5 * self.R
            self.dx = self.d
    
    Brendon Murphy's avatar
    Brendon Murphy committed
        def vert(self, row, col):
            # full cell
    
            if row >= 0 and row < self.rows and col >= 0 and col < self.cols:
                return [0, 1, 2, 3, 4, 5]
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            # right down corner
    
            if row == -1 and col == self.cols - 1:
                return [1, 2]
            if row == 0 and self.rows > 1 and col == self.cols:
                return [1, 2, 3]
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            # left down corner
    
            if row == -1 and col == -1:
                return [0, 1]
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            if self.rows % 2:
                # left up corner
    
                if row == self.rows and col == -1:
                    return [4, 5]
    
    Brendon Murphy's avatar
    Brendon Murphy committed
                # right up corner
    
                if row == self.rows and col == self.cols - 1:
                    return [3, 4]
                if row == self.rows - 1 and self.rows > 1 and col == self.cols:
                    return [2, 3, 4]
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            else:
                # left up corner
    
                if row == self.rows and col == 0:
                    return [4, 5]
                if row == self.rows - 1 and self.rows > 1 and col == -1:
                    return [0, 4, 5]
    
    Brendon Murphy's avatar
    Brendon Murphy committed
                # right up corner
    
                if row == self.rows and col == self.cols:
                    return [3, 4]
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            # horizontal lines
            if col >= 0 and col < self.cols:
    
                if row == -1:
                    return [0, 1, 2]
                if row == self.rows:
                    return [3, 4, 5]
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            # vertical lines
            if row >= 0 and row < self.rows:
                if col == -1:
    
                    if row % 2:
                        return [0, 1, 4, 5]
                    else:
                        return [0, 5]
    
    Brendon Murphy's avatar
    Brendon Murphy committed
                if col == self.cols:
    
                    if row % 2 or self.rows == 1:
                        return [2, 3]
                    else:
                        return [1, 2, 3, 4]
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            return []
    
    Brendon Murphy's avatar
    Brendon Murphy committed
        def cell(self, row, col, idx):
    
            cp = [self.sx + self.dx * col, self.sy + self.dy * row, 0]  # central point
            if row % 2:
                cp[0] += self.gx
            co = []  # vertices coords
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            vi = self.vert(row, col)
            ap = {}
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            for i in vi:
    
                a = pi / 6 + i * pi / 3  # angle
    
    Brendon Murphy's avatar
    Brendon Murphy committed
                ap[i] = idx + len(co)
                co.append((cp[0] + cos(a) * self.r, cp[1] + sin(a) * self.r, cp[2]))
            return co, ap
    
    Brendon Murphy's avatar
    Brendon Murphy committed
        def generate(self):
            ar = 1
            ac = 1
    
            cells = []
            verts = []
            faces = []
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            for row in range(-ar, self.rows + ar):
                level = []
                for col in range(-ac, self.cols + ac):
                    co, ap = self.cell(row, col, len(verts))
                    verts += co
                    level.append(ap)
                cells.append(level)
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            # bottom row
            row = 0
            for col in range(1, len(cells[row]) - 1):
                s = cells[row][col]
                l = cells[row][col - 1]
                u = cells[row + 1][col]
    
    Brendon Murphy's avatar
    Brendon Murphy committed
                faces.append((s[1], u[5], u[4], s[2]))
                faces.append((s[2], u[4], l[0]))
    
            # top row
            row = len(cells) - 1
            cs = 0
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            for col in range(1 + cs, len(cells[row]) - 1):
                s = cells[row][col]
                l = cells[row][col - 1]
                d = cells[row - 1][col - cs]
                faces.append((s[3], l[5], d[1]))
                faces.append([s[3], d[1], d[0], s[4]])
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            # middle rows
            for row in range(1, len(cells) - 1):
                cs = 0
    
    Brendon Murphy's avatar
    Brendon Murphy committed
                for col in range(1, len(cells[row]) - 1):
                    s = cells[row][col]
                    l = cells[row][col - 1]
                    u = cells[row + 1][col - cs]
                    d = cells[row - 1][col - cs]
    
    Brendon Murphy's avatar
    Brendon Murphy committed
                    faces.append((s[1], u[5], u[4], s[2]))
                    faces.append((s[2], u[4], l[0]))
                    faces.append([s[2], l[0], l[5], s[3]])
                    faces.append((s[3], l[5], d[1]))
                    faces.append([s[3], d[1], d[0], s[4]])
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            # right column
            row = 0
            col = len(cells[row]) - 1
            for row in range(1, len(cells) - 1):
                cs = 0
    
    Brendon Murphy's avatar
    Brendon Murphy committed
                s = cells[row][col]
                l = cells[row][col - 1]
                u = cells[row + 1][col - cs]
                d = cells[row - 1][col - cs]
    
    Brendon Murphy's avatar
    Brendon Murphy committed
                if row % 2 and row < len(cells) - 2:
                    faces.append((s[1], u[5], u[4], s[2]))
                faces.append((s[2], u[4], l[0]))
                faces.append([s[2], l[0], l[5], s[3]])
                faces.append((s[3], l[5], d[1]))
                if row % 2 and row > 1:
                    faces.append([s[3], d[1], d[0], s[4]])
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            # final fix
            if not self.rows % 2:
                row = len(cells) - 1
                s = cells[row][col]
                l = cells[row][col - 1]
                d = cells[row - 1][col - 1]
                faces.append((s[3], l[5], d[1]))
                faces.append([s[3], d[1], d[0], s[4]])
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            return verts, faces
    
    
    def edge_max(diam):
        return diam * sin(pi / 3)
    
    
    class add_mesh_honeycomb(bpy.types.Operator, object_utils.AddObjectHelper):
    
        bl_idname = "mesh.honeycomb_add"
        bl_label = "Add HoneyComb"
        bl_description = "Simple honeycomb mesh generator"
    
    Brendon Murphy's avatar
    Brendon Murphy committed
        bl_options = {'REGISTER', 'UNDO'}
    
        def fix_edge(self, context):
            m = edge_max(self.diam)
            if self.edge > m:
                self.edge = m
    
    
        HoneyComb : BoolProperty(name = "HoneyComb",
                    default = True,
                    description = "HoneyComb")
        change : BoolProperty(name = "Change",
                    default = False,
                    description = "change HoneyComb")
    
    
        rows: IntProperty(
    
                name="Num of rows",
                default=2,
                min=1, max=100,
                description='Number of the rows'
                )
    
        cols: IntProperty(
    
                name='Num of cols',
                default=2,
                min=1, max=100,
                description='Number of the columns'
                )
    
        diam: FloatProperty(
    
                name='Cell Diameter',
                default=1.0,
                min=0.0, update=fix_edge,
                description='Diameter of the cell'
                )
    
        edge: FloatProperty(
    
                name='Edge Width',
                default=0.1,
                min=0.0, update=fix_edge,
                description='Width of the edge'
                )
    
        def draw(self, context):
            layout = self.layout
    
            layout.prop(self, 'rows', expand=True)
            layout.prop(self, 'cols', expand=True)
            layout.prop(self, 'diam', expand=True)
            layout.prop(self, 'edge', expand=True)
    
            if self.change == False:
                col = layout.column(align=True)
                col.prop(self, 'align', expand=True)
                col = layout.column(align=True)
                col.prop(self, 'location', expand=True)
                col = layout.column(align=True)
                col.prop(self, 'rotation', expand=True)
    
    
    Brendon Murphy's avatar
    Brendon Murphy committed
        @classmethod
        def poll(cls, context):
            return context.scene is not None
    
    Brendon Murphy's avatar
    Brendon Murphy committed
        def execute(self, context):
    
            # turn off 'Enter Edit Mode'
            use_enter_edit_mode = bpy.context.preferences.edit.use_enter_edit_mode
            bpy.context.preferences.edit.use_enter_edit_mode = False
    
    
            if bpy.context.mode == "OBJECT":
                if context.selected_objects != [] and context.active_object and \
    
                    (context.active_object.data is not None) and ('HoneyComb' in context.active_object.data.keys()) and \
                    (self.change == True):
    
                    obj = context.active_object
                    oldmesh = obj.data
                    oldmeshname = obj.data.name
                    comb = honeycomb_geometry(self.rows, self.cols, self.diam, self.edge)
                    verts, faces = comb.generate()
                    mesh = bpy.data.meshes.new('HoneyComb')
                    mesh.from_pydata(verts, [], faces)
                    obj.data = mesh
                    for material in oldmesh.materials:
                        obj.data.materials.append(material)
                    bpy.data.meshes.remove(oldmesh)
                    obj.data.name = oldmeshname
                else:
                    comb = honeycomb_geometry(self.rows, self.cols, self.diam, self.edge)
                    verts, faces = comb.generate()
                    mesh = bpy.data.meshes.new('HoneyComb')
                    mesh.from_pydata(verts, [], faces)
                    obj = object_utils.object_data_add(context, mesh, operator=self)
    
                obj.data["HoneyComb"] = True
                obj.data["change"] = False
                for prm in HoneyCombParameters():
                    obj.data[prm] = getattr(self, prm)
    
            if bpy.context.mode == "EDIT_MESH":
                active_object = context.active_object
                name_active_object = active_object.name
                bpy.ops.object.mode_set(mode='OBJECT')
                comb = honeycomb_geometry(self.rows, self.cols, self.diam, self.edge)
                verts, faces = comb.generate()
                mesh = bpy.data.meshes.new('HoneyComb')
                mesh.from_pydata(verts, [], faces)
    
                obj = object_utils.object_data_add(context, mesh, operator=self)
    
                obj.select_set(True)
                active_object.select_set(True)
    
                bpy.context.view_layer.objects.active = active_object
    
                bpy.ops.object.join()
                context.active_object.name = name_active_object
                bpy.ops.object.mode_set(mode='EDIT')
    
            if use_enter_edit_mode:
                bpy.ops.object.mode_set(mode = 'EDIT')
    
            # restore pre operator state
            bpy.context.preferences.edit.use_enter_edit_mode = use_enter_edit_mode
    
    
    Brendon Murphy's avatar
    Brendon Murphy committed
            return {'FINISHED'}
    
    
    def HoneyCombParameters():
        HoneyCombParameters = [
            "rows",
            "cols",
            "diam",
            "edge",
            ]
        return HoneyCombParameters