Skip to content
Snippets Groups Projects
circle_array.py 5.25 KiB
Newer Older
  • Learn to ignore specific revisions
  • # gpl author: Antonis Karvelas
    
    # -*- coding: utf-8 -*-
    
    bl_info = {
        "name": "Circle Array",
        "author": "Antonis Karvelas",
        "version": (1, 0),
        "blender": (2, 6, 7),
        "location": "View3D > Object > Circle_Array",
        "description": "Uses an existing array and creates an empty, "
                       "rotates it properly and makes a Circle Array",
        "warning": "",
        "wiki_url": "",
        "tracker_url": "",
        "category": "Mesh"
        }
    
    
    import bpy
    from bpy.types import Operator
    from math import radians
    
    
    class Circle_Array(Operator):
        bl_label = "Circle Array"
        bl_idname = "objects.circle_array_operator"
        bl_description = ("Creates an Array Modifier with offset empty object\n"
                          "Works with Mesh, Curve, Text & Surface")
    
        @classmethod
        def poll(cls, context):
            return context.active_object is not None
    
        def check_empty_name(self, context):
            new_name, def_name = "", "EMPTY_C_Array"
            suffix = 1
            try:
                # first slap a simple linear count + 1 for numeric suffix, if it fails
                # harvest for the rightmost numbers and append the max value
                list_obj = []
                obj_all = context.scene.objects
                list_obj = [obj.name for obj in obj_all if obj.name.startswith(def_name)]
                new_name = "{}_{}".format(def_name, len(list_obj) + 1)
    
                if new_name in list_obj:
                    from re import findall
                    test_num = [findall("\d+", words) for words in list_obj]
                    suffix += max([int(l[-1]) for l in test_num])
                    new_name = "{}_{}".format(def_name, suffix)
                return new_name
            except:
                return None
    
        def execute(self, context):
            try:
                allowed_obj = ['MESH', 'CURVE', 'SURFACE', 'FONT']
                if context.active_object.type not in allowed_obj:
                    self.report(
                        {"WARNING"},
                        "Operation Cancelled. The active object is not of "
                        "Mesh, Curve, Surface or Font type"
                        )
                    return {'CANCELLED'}
    
                default_name = self.check_empty_name(context) or "EMPTY_C_Array"
                bpy.ops.object.modifier_add(type='ARRAY')
    
                if len(bpy.context.selected_objects) == 2:
                    list = bpy.context.selected_objects
                    active = list[0]
                    active.modifiers[0].use_object_offset = True
                    active.modifiers[0].use_relative_offset = False
                    active.select = False
                    bpy.context.scene.objects.active = list[0]
                    bpy.ops.view3d.snap_cursor_to_selected()
                    if active.modifiers[0].offset_object is None:
                        bpy.ops.object.add(type='EMPTY')
                        empty_name = bpy.context.active_object
                        empty_name.name = default_name
                        active.modifiers[0].offset_object = empty_name
                    else:
                        empty_name = active.modifiers[0].offset_object
    
                    bpy.context.scene.objects.active = active
                    num = active.modifiers["Array"].count
                    rotate_num = 360 / num
                    active.select = True
                    bpy.ops.object.transform_apply(location=False, rotation=True, scale=True)
                    empty_name.rotation_euler = (0, 0, radians(rotate_num))
                    empty_name.select = False
                    active.select = True
                    bpy.ops.object.origin_set(type="ORIGIN_CURSOR")
    
                    return {'FINISHED'}
                else:
                    active = context.active_object
                    active.modifiers[0].use_object_offset = True
                    active.modifiers[0].use_relative_offset = False
                    bpy.ops.view3d.snap_cursor_to_selected()
                    if active.modifiers[0].offset_object is None:
                        bpy.ops.object.add(type='EMPTY')
                        empty_name = bpy.context.active_object
                        empty_name.name = default_name
                        active.modifiers[0].offset_object = empty_name
                    else:
                        empty_name = active.modifiers[0].offset_object
    
                    bpy.context.scene.objects.active = active
                    num = active.modifiers["Array"].count
                    rotate_num = 360 / num
                    active.select = True
                    bpy.ops.object.transform_apply(location=False, rotation=True, scale=True)
                    empty_name.rotation_euler = (0, 0, radians(rotate_num))
                    empty_name.select = False
                    active.select = True
    
                    return {'FINISHED'}
            except Exception as e:
                self.report({'WARNING'},
                            "Circle Array operator could not be executed (See the console for more info)")
                print("\n[objects.circle_array_operator]\nError: {}\n".format(e))
    
                return {'CANCELLED'}
    
    
    # Register
    def circle_array_menu(self, context):
        self.layout.operator(Circle_Array.bl_idname, text="Circle_Array")
    
    
    def register():
        bpy.utils.register_class(Circle_Array)
        bpy.types.VIEW3D_MT_object.append(circle_array_menu)
    
    
    def unregister():
        bpy.utils.unregister_class(Circle_Array)
        bpy.types.VIEW3D_MT_object.remove(circle_array_menu)
    
    
    if __name__ == "__main__":
        register()