1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
# gpl author: Antonis Karvelas
# -*- coding: utf-8 -*-
bl_info = {
"name": "Circle Array",
"author": "Antonis Karvelas",
"version": (1, 0, 1),
"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):
is_allowed = True
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.scene.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.scene.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.scene.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.scene.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)
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 register():
bpy.utils.register_class(Circle_Array)
def unregister():
bpy.utils.unregister_class(Circle_Array)
if __name__ == "__main__":
register()
|