Skip to content
Snippets Groups Projects
circle_array.py 6.24 KiB
Newer Older
  • Learn to ignore specific revisions
  • # gpl author: Antonis Karvelas
    
    # -*- coding: utf-8 -*-
    
    bl_info = {
        "name": "Circle Array",
        "author": "Antonis Karvelas",
    
        "blender": (2, 67, 0),
    
        "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": "",
        "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 and Surface\n"
                          "Use an object with an existing Array modifier\n"
                          "or rotate the newly created Empty with the name pattern\n"
                          "EMPTY_C_Array_ if the Array doesn't exist (angle: 360/Count)")
    
    
        @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']
    
                for obj in context.selected_objects:
                    if obj.type not in allowed_obj:
                        is_allowed = False
                        break
    
                if not is_allowed:
    
                    self.report(
                        {"WARNING"},
    
                        "The Active/Selected objects are not of "
                        "Mesh, Curve, Surface or Font type. Operation Cancelled"
    
                        )
                    return {'CANCELLED'}
    
                default_name = self.check_empty_name(context) or "EMPTY_C_Array"
                bpy.ops.object.modifier_add(type='ARRAY')
    
    
                if len(context.selected_objects) == 2:
                    selected = context.selected_objects
                    lists = [obj for obj in selected if obj != context.active_object]
                    active = lists[0]
                    # check if the list object has a modifier
                    check_mod = None
                    for mod in active.modifiers[:]:
                        if mod.type == "ARRAY":
                            check_mod = mod
                            break
    
                    if check_mod:
                        check_mod.use_object_offset = True
                        check_mod.use_relative_offset = False
                    else:
                        # fallback
    
                        bpy.context.view_layer.objects.active = active
    
                        bpy.ops.object.modifier_add(type='ARRAY')
                        active.modifiers[0].use_object_offset = True
                        active.modifiers[0].use_relative_offset = False
    
    
                    active.modifiers[0].use_object_offset = True
                    active.modifiers[0].use_relative_offset = False
    
                    active.select_set(False)
    
                    bpy.context.view_layer.objects.active = context.active_object
    
                    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.view_layer.objects.active = active
    
                    num = active.modifiers["Array"].count
                    rotate_num = 360 / num
    
                    active.select_set(True)
    
                    bpy.ops.object.transform_apply(location=False, rotation=True, scale=True)
                    empty_name.rotation_euler = (0, 0, radians(rotate_num))
    
                    empty_name.select_set(False)
                    active.select_set(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.view_layer.objects.active = active
    
                    num = active.modifiers["Array"].count
                    rotate_num = 360 / num
    
                    active.select_set(True)
    
                    bpy.ops.object.transform_apply(location=False, rotation=True, scale=True)
                    empty_name.rotation_euler = (0, 0, radians(rotate_num))
    
                    empty_name.select_set(False)
                    active.select_set(True)
    
            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 register():
        bpy.utils.register_class(Circle_Array)
    
    
    def unregister():
        bpy.utils.unregister_class(Circle_Array)
    
    
    if __name__ == "__main__":
        register()