zeffii / mesh_tiny_cad

a tiny set of unmissable CAD functions ( VTX, XALL ...) for Blender

Home Page:http://zeffii.github.io/mesh_tiny_cad/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

soft array

zeffii opened this issue · comments

sometimes a modifier is too much, this has linear and radial array

import bpy
import bmesh
import math
import mathutils
from mathutils import Vector

def main(self, context):

    if not self.duplicates > 1:
        return

    obj = bpy.context.edit_object
    me = obj.data
    bm = bmesh.from_edit_mesh(me)

    copy_geom_faces = [f for f in bm.faces if f.select and not f.hide]
    num_faces = len(copy_geom_faces)

    def offset_face(face):
        for i in range(1, self.duplicates):
            new_verts = []
            for v in face.verts:
                plus_vector = Vector((self.f_x * i, self.f_y * i, self.f_z * i))
                nv = bm.verts.new(v.co + plus_vector)
                new_verts.append(nv)
            bm.faces.new(new_verts)

    def rotate_face(face):
        axis = mathutils.Vector(self.plane[:]).normalized()
        theta = math.radians(self.radial_degrees) / self.duplicates
        view = context.space_data
        for i in range(1, self.duplicates):
            new_verts = []
            mat_rot = mathutils.Matrix.Rotation(theta * i, 4, axis)

            if not self.use_cursor:
                for v in face.verts:
                    vec = mat_rot * v.co
                    nv = bm.verts.new(vec)
                    new_verts.append(nv)
            else:
                for v in face.verts:
                    vec = mat_rot * (v.co + obj.location - view.cursor_location)
                    nv = bm.verts.new(vec + view.cursor_location - obj.location)
                    new_verts.append(nv)
            bm.faces.new(new_verts)


    if num_faces > 0:
        if not self.radial_array:
            for face in copy_geom_faces:
                offset_face(face)
        else:
            for face in copy_geom_faces:
                rotate_face(face)

    if self.recalc:
        # could also operate on faces=new_faces ... bm.faces might be overkill
        bmesh.ops.recalc_face_normals(bm, faces=bm.faces)
    bmesh.update_edit_mesh(me, True, destructive=True)



class SimpleOperator(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "object.array_operator"
    bl_label = "Simple Array Operator"
    bl_options = {'REGISTER', 'UNDO'}
    bl_icon = 'TEXT'

    f_x = bpy.props.FloatProperty()
    f_y = bpy.props.FloatProperty()
    f_z = bpy.props.FloatProperty()
    plane = bpy.props.FloatVectorProperty(default=(0,0,1), subtype='XYZ')
    duplicates = bpy.props.IntProperty(min=0)
    recalc = bpy.props.BoolProperty()
    radial_array = bpy.props.BoolProperty()
    radial_degrees = bpy.props.FloatProperty(default=360)
    use_cursor = bpy.props.BoolProperty()

    def draw(self, context):
        l = self.layout
        c = l.column()
        icon = ['MOD_ARRAY', 'FORCE_FORCE'][self.radial_array]
        c.prop(self, 'radial_array', toggle=True, icon=icon)

        if not self.radial_array:
            c.prop(self, 'f_x')
            c.prop(self, 'f_y')        
            c.prop(self, 'f_z')        
        else:
            view = context.space_data
            c.prop(self, 'use_cursor', text='pivot around cursor')
            if self.use_cursor:
                c.prop(view, "cursor_location", text="Location")
            c.prop(self, 'plane')
            c.prop(self, 'radial_degrees')

        c.prop(self, 'duplicates')
        c.prop(self, 'recalc')


    @classmethod
    def poll(cls, context):
        return context.active_object is not None

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


def register():
    bpy.utils.register_class(SimpleOperator)


def unregister():
    bpy.utils.unregister_class(SimpleOperator)


if __name__ == "__main__":
    register()