Circle Array Add-On

Works for me(2.67b). Postpone suicide and thank you.

EDIT: One suggestion though. If you use circle array, then change the number in the array and use the circle array again, it creates a new unused empty. Maybe check the modifier to see if the empty has already be assigned before creating a new one?

tried it on window 32
and it does take the square shape
but still have the planes at different level like the empty is not located where it should be in Z

not certain but the empty i think should be set at same level then the object center!

if it can work nicely this is a nice addon
it is a bit like spin dup but way faster and can be change i guess!

thanks for feedback

Well, are you sure you are doing it the right way?
the empty is always located in the object origin, so no problem with Z. Check if you REALLY have the latest version, I had to play around a bit for the new version to be installed.
It’s not the add-on, surely, it works for me(and for cmomoney, as it seems…).
Could you upload you .blend file or something?

im uploaded the last version you did

i started script then added array with count = 4
then in object menu set circle
and not really working well!

here is file

circlearray1.blend (404 KB)

unless i’m not doing the right sequences of commands!
let me know

thanks

As soon as object is added with Z not equal to 0… Or do you expect it always be added on 0,0,0 ?

Okay, I was able to replicate the problem. As stated, if the object is moved away from 0,0,0, the array is not circling the object’s origin. What I see happening is the empty is indeed being placed at the object’s origin. But the origin actually moves to 0,0,0. If z is still at 0, you still get a circle, just not where expected. If z is not at 0, you get more of a spiral.

Now I get it… Well, I tried to fix it, but I can’t! Not sure what’s going on…
Is there anyone with Python knowledge who can take a look?
For the time being, everything has to be done in the centre of the grid.
Sorry for that…

don’t understand why the center is changing location!

is this a bug in API ?

thanks

Try commenting out both of the last apply_transform operators.

Yep, i got to the same point after some tinkering…Not much into python and bpy - might look funny for some:


import bpy
from math import radians
act_obj = bpy.context.active_object
act_obj.modifiers[0].use_object_offset = True 
act_obj.modifiers[0].use_relative_offset = False
saved_location = bpy.context.scene.cursor_location.copy()
bpy.context.scene.cursor_location = bpy.context.active_object.location

bpy.ops.object.add(type='EMPTY')
empty_name = bpy.context.active_object
empty_name.name = "EMPTY" 
bpy.context.scene.objects.active = act_obj
act_obj.modifiers[0].offset_object = empty_name
bpy.context.scene.cursor_location = saved_location 

num = act_obj.modifiers["Array"].count
bpy.context.scene.objects.active = empty_name
bpy.context.scene.objects.active.rotation_euler=(0,0,radians(360 / num))
bpy.context.scene.objects.active = act_obj
bpy.context.scene.objects.active.select = True

# Go edit mode and move mesh x,y to make circle; empty - z, to make "spiral stairs"

This is what worked for me. I also added a check to keep from making extra empties if you reuse the script(like when adjusting the array count):


# -*- coding: utf-8 -*-

bl_info = {  
     "name": "Circle Array",  
     "author": "Antonis Karvelas",  
     "version": (1, 0),  
     "blender": (2, 6, 6),  
     "location": "View3D > Object > Circle_Array",  
     "description": "Uses an existing array and creates an empty,rotates it properly and makes a Circle Array ",  
     "warning": "You must have an object and an array, or two objects, with only the first having an array",  
     "wiki_url": "",  
     "tracker_url": "",  
     "category": "Mesh"}  


import bpy
from math import radians

class Circle_Array(bpy.types.Operator):
    bl_label = "Circle Array"
    bl_idname = "objects.circle_array_operator"
             
    def execute(self, context):
                
        if len(bpy.context.selected_objects) == 2:
            list = bpy.context.selected_objects
            active = bpy.context.active_object
            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 == None:
                bpy.ops.object.add(type='EMPTY')
                empty_name = bpy.context.active_object
                empty_name.name = "EMPTY"
                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
            print(num)
            rotate_num = 360 / num
            print(rotate_num)
            active.select = True
            bpy.ops.object.transform_apply(location = False, rotation = True, scale = False) 
            empty_name.rotation_euler = (0, 0, radians(rotate_num))
            empty_name.select = False
            active.select = True
            bpy.ops.object.origin_set(type="ORIGIN_CURSOR")
            #bpy.ops.object.transform_apply(location = True, rotation = False, scale = True)
            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 == None:
                bpy.ops.object.add(type='EMPTY')
                empty_name = bpy.context.active_object
                empty_name.name = "EMPTY"
                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
            print(num)
            rotate_num = 360 / num
            print(rotate_num)
            active.select = True
            bpy.ops.object.transform_apply(location = False, rotation = True, scale = False) 
            empty_name.rotation_euler = (0, 0, radians(rotate_num))
            empty_name.select = False
            active.select = True
            #bpy.ops.object.transform_apply(location = True, rotation = False, scale = True) 
            return {'FINISHED'} 
        
            
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)  
    
if __name__ == "__main__":
    register()

did a new test

here is result


if you use apply location it will change the ob’s origin back to 0,0,0!

thanks

here is a way which seems to work only if the object is located at origin 0,0,0
for a plane 1 X 2

empty_name.rotation_euler = (0, 0, radians(rotate_num))
empty_name.location.x=1
empty_name.location.y=1
empty_name.select = False

so needs to move the empty relative to the object’s location
but could be function of box size of the object!

have to find way of doing this!

thanks

You probably wouldn’t want to apply the location until you apply the array modifier.

Programming = Headache sometimes
When I find some time, I have to clear the ideas and create a working add-on…
Patience, last week of exams!!!
BTW, nice Empty Checker, but, if you use array with two objects and then with one object, or the opposite, no new empty is created, while it should…
Thank you all for your wonderfull ideas!

do your exams first
then next week or 2 you can come back on this

thanks

Good news: the exams are over!!!
Bad news: I’m at bed with a fever and writing this message with mu kindle…
What else could possibly go wrong? XD

So, after heroic efforts to get up from bed, I finally seem to have fixed all the problem…
So, here’s the code:


# -*- 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": "You must have an object and an array, or two objects, with only the first having an array",  
     "wiki_url": "",  
     "tracker_url": "",  
     "category": "Mesh"}  




import bpy
from math import radians


class Circle_Array(bpy.types.Operator):
    bl_label = "Circle Array"
    bl_idname = "objects.circle_array_operator"
             
    def execute(self, context):
                
        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 == None:
                bpy.ops.object.add(type='EMPTY')
                empty_name = bpy.context.active_object
                empty_name.name = "EMPTY"
                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
            print(num)
            rotate_num = 360 / num
            print(rotate_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 == None:
                bpy.ops.object.add(type='EMPTY')
                empty_name = bpy.context.active_object
                empty_name.name = "EMPTY"
                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
            print(num)
            rotate_num = 360 / num
            print(rotate_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'} 
        
            
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)  
    
if __name__ == "__main__":
    register()

And here’s my proof that it works (with any rotation, location or scale):


Feel free to change the code and new ideas are always welcome. After all, we are a community, aren’t we :slight_smile:
Thank you all for your ideas and support!
Python File: Circle_Array_AddOn.py.zip (1.07 KB)

Normally with add ons like this, there is a place to download the .py file … I see you posted the actual code instead.

Can someone just quickly tell me what I should do to try out this add on? I’m guessing I copy the code from this page… but then what?

Paste it into a text editor(Notepad) and save it as Circle_Array.py