mirror of http://CODE.RHODECODE.COM/u/O/O/O
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1223 lines
44 KiB
1223 lines
44 KiB
# -*- coding: utf-8 -*- |
|
import bpy |
|
import math |
|
|
|
from bpy.types import PropertyGroup |
|
from mathutils import Vector |
|
|
|
from . import cfg |
|
from . import at_panel |
|
from . import at_operators |
|
from . at_calc_func import( |
|
x_axis, |
|
y_axis, |
|
z_axis, |
|
xyz_axis, |
|
at_all_in_one, |
|
at_random, |
|
sum_serie, |
|
tsr |
|
) |
|
|
|
"""not used yet |
|
if check on update, may really slow the addon """ |
|
def check_list(alist): |
|
"""check all the objects""" |
|
for elem in alist: |
|
if elem in bpy.data.objects: |
|
pass |
|
else: |
|
cfg.display_error(str(elem)+" isn't valid.") |
|
print("Check_list : a name isn't valid ", elem) |
|
return False |
|
return True |
|
|
|
|
|
def elem_in_row(column, row, indice): |
|
"""Number of elements in a row""" |
|
elements = column + (row - 1) * indice |
|
# print("row elements =", elements) |
|
return elements |
|
|
|
|
|
# ---------------------------- Properties --------------------------- |
|
class ArrayTools_props(PropertyGroup): |
|
"""Properties for array tools""" |
|
|
|
def add_in_column(self, row, nb_column=-1): |
|
"""Add nb_column element(s) in each row""" |
|
column = cfg.at_count_values[0] |
|
if nb_column == -1: |
|
nb_column = cfg.at_count_values[1] - column |
|
|
|
ref_name = cfg.atools_objs[0][0] |
|
if ref_name in bpy.data.objects: |
|
ref_obj = bpy.data.objects[ref_name] |
|
# update the ref_mtx if object's transforms have changed |
|
cfg.ref_mtx = ref_obj.matrix_world.copy() |
|
# with offset no need to replace all elements, only the last |
|
if self.is_tr_off_last: |
|
for i in range(row): |
|
col = column + i*self.alter |
|
for j in range(col, col + nb_column): |
|
objcp = ref_obj.copy() |
|
array_col = bpy.data.collections.get(cfg.col_name) |
|
array_col.objects.link(objcp) |
|
if self.is_copy: |
|
objcp.data = ref_obj.data.copy() |
|
cfg.atools_objs[i].append(objcp.name) |
|
|
|
self.transforms_lsr(j, i, cfg.ref_mtx, objcp.name) |
|
# update the global ui |
|
tr, sc, rot = self.calc_global() |
|
self.up_ui_tr_global(tr) |
|
self.up_ui_sc_global(sc) |
|
self.up_ui_rot_global(rot) |
|
|
|
else: # replace all elements |
|
for i in range(row): |
|
col = column + i*self.alter |
|
for j in range(col, col + nb_column): |
|
objcp = ref_obj.copy() |
|
array_col = bpy.data.collections.get(cfg.col_name) |
|
array_col.objects.link(objcp) |
|
if self.is_copy: |
|
objcp.data = ref_obj.data.copy() |
|
cfg.atools_objs[i].append(objcp.name) |
|
self.update_global(bpy.context) |
|
del objcp |
|
del ref_obj |
|
else: |
|
message = "Problem with reference object's name." |
|
cfg.display_error(message) |
|
print("Error in 'add_in_column' : ", message) |
|
|
|
|
|
def del_in_column(self, row, nb_column=-1): |
|
"""Remove nb_column element(s) in each row""" |
|
if nb_column == -1: |
|
nb_column = cfg.at_count_values[0] - cfg.at_count_values[1] |
|
array_col = bpy.data.collections.get(cfg.col_name) |
|
for i in range(row-1, -1, -1): |
|
for j in range(nb_column): |
|
del_name = cfg.atools_objs[i].pop() |
|
if del_name in bpy.data.objects: |
|
obj = bpy.data.objects[del_name] |
|
array_col.objects.unlink(obj) |
|
bpy.data.objects.remove(obj, do_unlink=True) |
|
else: |
|
cfg.display_error(del_name + " doesn't exist anymore.") |
|
print("Error in 'del_in_column' : ", del_name) |
|
|
|
# if no more element in list, remove the row |
|
if not cfg.atools_objs[i]: |
|
cfg.atools_objs.pop() |
|
self.up_ui_updateRow(row - 1) |
|
continue |
|
if not self.is_tr_off_last: |
|
# if global is used last |
|
self.update_global(bpy.context) |
|
else: |
|
tr, sc, rot = self.calc_global() |
|
self.up_ui_tr_global(tr) |
|
self.up_ui_sc_global(sc) |
|
self.up_ui_rot_global(rot) |
|
|
|
|
|
def add_in_col_alter(self, row, nb_column): |
|
"""Add elements in all rows except the first for variation""" |
|
array_col = bpy.data.collections.get(cfg.col_name) |
|
ref_name = cfg.atools_objs[0][0] |
|
column = self.count |
|
if ref_name in bpy.data.objects: |
|
ref_obj = bpy.data.objects[ref_name] |
|
cfg.ref_mtx = ref_obj.matrix_world.copy() |
|
if self.is_tr_off_last: |
|
for i in range(1, row): |
|
for j in range(column, column + i * nb_column): |
|
objcp = ref_obj.copy() |
|
array_col = bpy.data.collections.get(cfg.col_name) |
|
array_col.objects.link(objcp) |
|
if self.is_copy: |
|
objcp.data = ref_obj.data.copy() |
|
cfg.atools_objs[i].append(objcp.name) |
|
# print("objs=", cfg.atools_objs) |
|
|
|
self.update_offset(bpy.context) |
|
else: # replace all elements |
|
for i in range(1, row): |
|
for j in range(column, column + i * nb_column): |
|
objcp = ref_obj.copy() |
|
array_col = bpy.data.collections.get(cfg.col_name) |
|
array_col.objects.link(objcp) |
|
if self.is_copy: |
|
objcp.data = ref_obj.data.copy() |
|
cfg.atools_objs[i].append(objcp.name) |
|
self.update_global(bpy.context) |
|
del objcp |
|
del ref_obj |
|
else: |
|
message = "Problem with reference object's name." |
|
cfg.display_error(message) |
|
print("Error in 'add_in_column' : ", message) |
|
|
|
|
|
def del_in_col_alter(self, row, nb_column): |
|
"""Remove elements in all rows except the first""" |
|
array_col = bpy.data.collections.get(cfg.col_name) |
|
for i in range(row -1 , 0, -1): |
|
for j in range(nb_column * i): |
|
del_name = cfg.atools_objs[i].pop() |
|
# print("del name=", del_name) |
|
if del_name in bpy.data.objects: |
|
obj = bpy.data.objects[del_name] |
|
array_col.objects.unlink(obj) |
|
bpy.data.objects.remove(obj, do_unlink=True) |
|
else: |
|
cfg.display_error(del_name + " doesn't exist anymore.") |
|
print("Error in 'del_in_column' : ", del_name) |
|
if self.is_tr_off_last: |
|
self.update_offset(bpy.context) |
|
else: |
|
self.update_global(bpy.context) |
|
|
|
def add_in_row(self, column, nb_row=-1): |
|
"""Add column elements in nb_row new row(s)""" |
|
row = cfg.at_row_values[0] |
|
if nb_row == -1: |
|
nb_row = cfg.at_row_values[1] - row |
|
|
|
ref_name = cfg.atools_objs[0][0] |
|
if ref_name in bpy.data.objects: |
|
ref_obj = bpy.data.objects[ref_name] |
|
cfg.ref_mtx = ref_obj.matrix_world.copy() |
|
if self.is_tr_off_last: |
|
for i in range(row, row + nb_row): |
|
cfg.atools_objs.append([]) |
|
for j in range(column + i*self.alter): |
|
objcp = ref_obj.copy() |
|
array_col = bpy.data.collections.get(cfg.col_name) |
|
array_col.objects.link(objcp) |
|
if self.is_copy: |
|
objcp.data = ref_obj.data.copy() |
|
cfg.atools_objs[i].append(objcp.name) |
|
self.transforms_lsr(j, i, cfg.ref_mtx, objcp.name) |
|
else: |
|
for i in range(row, row + nb_row): |
|
cfg.atools_objs.append([]) |
|
for j in range(column): |
|
objcp = ref_obj.copy() |
|
array_col = bpy.data.collections.get(cfg.col_name) |
|
array_col.objects.link(objcp) |
|
if self.is_copy: |
|
objcp.data = ref_obj.data.copy() |
|
cfg.atools_objs[i].append(objcp.name) |
|
self.update_global(bpy.context) |
|
else: |
|
message = "Problem with reference object's name." |
|
cfg.display_error(message) |
|
print("Error in 'add in row' : ", message) |
|
|
|
|
|
def del_in_row(self, nb_row=-1): |
|
"""Remove nb_row row(s) : (column * nb_row) elements""" |
|
if nb_row == -1: |
|
nb_row = cfg.at_row_values[0] - cfg.at_row_values[1] |
|
array_col = bpy.data.collections.get(cfg.col_name) |
|
for i in range(nb_row): |
|
names = cfg.atools_objs.pop() |
|
for del_name in names: |
|
if del_name in bpy.data.objects: |
|
obj = bpy.data.objects[del_name] |
|
array_col.objects.unlink(obj) |
|
bpy.data.objects.remove(obj, do_unlink=True) |
|
else: |
|
cfg.display_error(del_name + " doesn't exist anymore.") |
|
print("Error in 'del_in_column' : ", del_name) |
|
|
|
|
|
def at_del_all(self, del_rall): |
|
"""Delete all copies and remove objects from lists |
|
del_rall : boolean, True to del reference object from list |
|
""" |
|
array_col = bpy.data.collections.get(cfg.col_name) |
|
ref_name = cfg.atools_objs[0][0] |
|
for i in range(self.row): |
|
names = cfg.atools_objs.pop() |
|
for obj_name in reversed(names): |
|
if obj_name == ref_name: |
|
continue |
|
# test if object exist |
|
if obj_name in bpy.data.objects: |
|
obj = bpy.data.objects[obj_name] |
|
array_col.objects.unlink(obj) |
|
bpy.data.objects.remove(obj, do_unlink=True) |
|
else: |
|
cfg.display_error(obj_name + " not exist!") |
|
print("Error in 'del_all' : ", obj_name) |
|
|
|
if del_rall: |
|
cfg.atools_objs.clear() |
|
|
|
# removing the collection if empty |
|
if not array_col.objects: |
|
bpy.data.collections.remove(array_col) |
|
else: |
|
cfg.atools_objs.append([ref_name]) |
|
# print("Del_all done!") |
|
|
|
# ----------------------- UI update ----------------------------- |
|
# --------------------------------------------------------------- |
|
# ----------------------- count update -------------------------- |
|
def updateCount(self, context): |
|
"""update the number of element(s) in column""" |
|
if self.is_prog_change: |
|
self.is_prog_change = False |
|
else: |
|
cfg.add_count(int(self.count)) |
|
cfg.del_count() |
|
|
|
# cfg.count_values[0] always store old count value |
|
difference = self.count - cfg.at_count_values[0] |
|
|
|
self.update_infos() |
|
|
|
if difference > 0: |
|
self.add_in_column(self.row, difference) |
|
elif difference < 0: |
|
self.del_in_column(self.row, -difference) |
|
# print("objs =", cfg.atools_objs) |
|
|
|
|
|
def up_ui_updateCount(self, val): |
|
"""Update the value of the property count in UI""" |
|
self.is_prog_change = True |
|
self.count = val |
|
|
|
# ----------------------- row update ---------------------------- |
|
def update_row(self, context): |
|
"""Update row property""" |
|
cfg.add_row(self.row) |
|
cfg.del_row() |
|
if self.is_prog_change: |
|
self.is_prog_change = False |
|
else: |
|
if self.alter < 0 and cfg.maxrow < self.row: |
|
cfg.display_error("Maximun rows for these setting is : " + str(cfg.maxrow)) |
|
self.up_ui_updateRow(cfg.maxrow) |
|
return |
|
|
|
# cfg.at_row_values[0] always store old row value |
|
difference = self.row - cfg.at_row_values[0] |
|
if difference > 0: |
|
self.add_in_row(self.count, difference) |
|
elif difference < 0: |
|
self.del_in_row(-difference) |
|
|
|
line = elem_in_row(self.count, self.row, self.alter) |
|
|
|
self.update_infos() |
|
|
|
def up_ui_updateRow(self, val): |
|
"""Update the value of the property row in UI""" |
|
self.is_prog_change = True |
|
self.row = val |
|
|
|
def update_alter(self, context): |
|
"""Update alter property""" |
|
if self.is_prog_change: |
|
self.is_prog_change = False |
|
else: |
|
# alter must have at least 2 rows |
|
if self.row == 1 and self.alter != 0: |
|
cfg.display_error("Add more rows first.") |
|
self.up_ui_updateAlter(0) |
|
return |
|
if self.alter < 0: |
|
# (column + (row-1)* variation) is the number of elements |
|
# of the last row and must be at least >= 1 |
|
alter = int((1 - self.count) / (self.row - 1)) |
|
if self.alter < alter: |
|
cfg.display_error("Min variation is '"+str(alter)+"' for these settings.") |
|
self.up_ui_updateAlter(alter) |
|
return |
|
|
|
cfg.add_alter(self.alter) |
|
cfg.del_alter() |
|
self.update_ralign() |
|
|
|
difference = self.alter - cfg.at_alter[0] |
|
if difference > 0: |
|
self.add_in_col_alter(self.row, difference) |
|
elif difference < 0: |
|
self.del_in_col_alter(self.row, -difference) |
|
# print(f"count={self.count}, row={self.row}, alter={self.alter}") |
|
line = elem_in_row(self.count, self.row, self.alter) |
|
# print("elems in row =", line) |
|
|
|
self.update_infos() |
|
|
|
|
|
def up_ui_updateAlter(self, val): |
|
"""Update the value of the property alter in UI""" |
|
self.is_prog_change = True |
|
self.alter = val |
|
|
|
|
|
def update_ralign(self): |
|
"""Update the value of ralign""" |
|
decal = -self.alter * self.tr_offset |
|
if self.align == 'LEFT': |
|
self.ralign = Vector((0.0, 0.0, 0.0)) |
|
elif self.align == 'CENTER': |
|
self.ralign = decal / 2 |
|
elif self.align == 'RIGHT': |
|
self.ralign = decal |
|
|
|
|
|
def update_align(self, context): |
|
"""According to the value of align, calculate ralign""" |
|
self.update_ralign() |
|
|
|
if self.is_tr_off_last: |
|
self.update_offset(bpy.context) |
|
else: |
|
self.update_global(bpy.context) |
|
|
|
|
|
def update_infos(self): |
|
"""Update properties total and erow""" |
|
sum = sum_serie(self.row, self.alter) |
|
square = self.count * self.row |
|
if self.alter >= 0: |
|
cfg.maxrow = self.row |
|
else: |
|
ca = self.count // -self.alter |
|
cfg.maxrow = ca if self.count % self.alter == 0 else ca + 1 |
|
self.total = str(int(square + sum)) |
|
self.erow = str(elem_in_row(self.count, self.row, self.alter)) |
|
|
|
# ----------------------- translation update -------------------- |
|
def up_ui_tr_offset(self, val): |
|
"""Update the value of the property tr_offset in UI""" |
|
self.is_prog_change = True |
|
self.tr_offset = val |
|
|
|
def up_ui_tr_global(self, val): |
|
"""Update the value of the property tr_global in UI""" |
|
self.is_prog_change = True |
|
self.tr_global = val |
|
|
|
# ----------------------- scale update -------------------------- |
|
def up_ui_sc_offset(self, val): |
|
"""Update the value of the property sc_offset in UI""" |
|
self.is_prog_change = True |
|
self.sc_offset = val |
|
|
|
def up_ui_sc_global(self, val): |
|
"""Update the value of the property sc_global in UI""" |
|
self.is_prog_change = True |
|
self.sc_global = val |
|
|
|
# ----------------------- rotation update ----------------------- |
|
def up_ui_rot_offset(self, val): |
|
"""Update the value of the property rot_offset in UI""" |
|
self.is_prog_change = True |
|
self.rot_offset = val |
|
|
|
def up_ui_rot_global(self, val): |
|
"""Update the value of the property rot_global in UI""" |
|
self.is_prog_change = True |
|
self.rot_global = val |
|
|
|
# --------------------------------------------------------------- |
|
def calc_global(self): |
|
"""Calculate global for column""" |
|
tg = (self.count-1) * self.tr_offset |
|
sg = (xyz_axis() - (self.count-1) * |
|
(cfg.ref_mtx.to_scale() - (self.sc_offset/100))) * 100 |
|
rg = self.count * Vector(self.rot_offset) |
|
return tg,sg,rg |
|
|
|
|
|
def transforms_lsr(self, column, row, mat, ename): |
|
"""Calculate transforms according to the position of the element |
|
column : indice of the element's column |
|
row : indice of the element's row |
|
mat : matrix of the reference object |
|
ename : element's name to put in place |
|
""" |
|
localxyz = (x_axis(), y_axis(), z_axis()) |
|
|
|
translate, scaling, rotate = tsr(mat, column, row, self.tr_offset, self.tr_second, |
|
self.sc_offset, self.sc_second, self.rot_offset, self.rot_second, self.ralign) |
|
if ename in bpy.data.objects: |
|
obj = bpy.data.objects[ename] |
|
if self.at_pivot is not None: |
|
obj.matrix_world = at_all_in_one(mat, rotate, localxyz, translate, |
|
scaling, self.at_pivot.location) |
|
else: |
|
obj.matrix_world = at_all_in_one(mat, rotate, localxyz, translate, |
|
scaling, mat.translation) |
|
|
|
|
|
def apply_transforms(self, matx, nb_column, nb_row, tr, sc, rot): |
|
"""Move, scale and rotate the selected elements |
|
tr : translation offset of the first row |
|
sc : scale offset of the first row |
|
rot : rotation offset of the first row |
|
return global transforms |
|
""" |
|
# local axis always (1,0,0) (0,1,0) (0,0,1) |
|
localxyz = (x_axis(), y_axis(), z_axis()) |
|
|
|
ref_scale = matx.to_scale() |
|
# duplicate code but avoid looping the test |
|
if self.at_pivot is not None: |
|
for i in range(nb_row): |
|
for j in range(nb_column + i*self.alter): |
|
elem = cfg.atools_objs[i][j] |
|
if elem in bpy.data.objects: |
|
obj = bpy.data.objects[elem] |
|
else: |
|
cfg.display_error(elem + " no more exist !") |
|
print("Error in 'apply_transforms', name no more exist : ", elem) |
|
continue |
|
t_off, s_off, r_off = tsr(matx, j, i, tr, self.tr_second, sc, |
|
self.sc_second, rot, self.rot_second, self.ralign) |
|
|
|
obj.matrix_world = at_all_in_one(matx, r_off, |
|
localxyz, t_off, s_off, self.at_pivot.location) |
|
else: |
|
for i in range(nb_row): |
|
for j in range(nb_column + i*self.alter): |
|
ref_loc = cfg.ref_mtx.translation |
|
elem = cfg.atools_objs[i][j] |
|
if elem in bpy.data.objects: |
|
obj = bpy.data.objects[elem] |
|
else: |
|
cfg.display_error(elem + " no more exist !") |
|
print("Error in 'apply_transforms', name no more exist : ", elem) |
|
continue |
|
t_off, s_off, r_off = tsr(matx, j, i, tr, self.tr_second, sc, |
|
self.sc_second, rot, self.rot_second, self.ralign) |
|
|
|
obj.matrix_world = at_all_in_one(matx, r_off, |
|
localxyz, t_off, s_off, ref_loc) |
|
tr_col,sc_col,rot_col = self.calc_global() |
|
return(tr_col, sc_col, rot_col) |
|
|
|
def update_offset(self, context): |
|
"""Update for all offsets""" |
|
if self.is_prog_change: |
|
self.is_prog_change = False |
|
else: # user change offset |
|
self.is_tr_off_last = True |
|
|
|
ref_name = cfg.atools_objs[0][0] |
|
if bpy.data.objects[ref_name]: |
|
cfg.ref_mtx = bpy.data.objects[ref_name].matrix_world.copy() |
|
aloc, asc, arot = self.apply_transforms(cfg.ref_mtx, self.count, self.row, |
|
self.tr_offset, self.sc_offset, Vector(self.rot_offset)) |
|
|
|
# since offset changes, global too |
|
self.up_ui_tr_global(aloc) |
|
self.up_ui_sc_global(asc) |
|
self.up_ui_rot_global(arot) |
|
|
|
|
|
def update_global(self, context): |
|
"""Update for all globals""" |
|
if self.is_prog_change: |
|
self.is_prog_change = False |
|
else: # user change global |
|
self.is_tr_off_last = False |
|
|
|
ref_name = cfg.atools_objs[0][0] |
|
if bpy.data.objects[ref_name]: |
|
cfg.ref_mtx = bpy.data.objects[ref_name].matrix_world.copy() |
|
ref_scale = cfg.ref_mtx.to_scale() |
|
|
|
translation_offset = Vector(self.tr_global) / (self.count - 1) |
|
scale_offset = ref_scale - ((ref_scale-(self.sc_global/100)) / (self.count - 1)) |
|
rotation_offset = Vector(self.rot_global) / self.count |
|
|
|
self.apply_transforms(cfg.ref_mtx, self.count, self.row, translation_offset, |
|
Vector(scale_offset)*100, rotation_offset) |
|
|
|
# since global changes, offset too |
|
self.up_ui_tr_offset(translation_offset) |
|
self.up_ui_sc_offset(Vector(scale_offset*100)) |
|
self.up_ui_rot_offset(rotation_offset) |
|
|
|
|
|
def update_second(self, context): |
|
"""Update the secondary transforms""" |
|
ref_name = cfg.atools_objs[0][0] |
|
if bpy.data.objects[ref_name]: |
|
cfg.ref_mtx = bpy.data.objects[ref_name].matrix_world.copy() |
|
self.apply_transforms(cfg.ref_mtx, self.count, self.row, self.tr_offset, |
|
self.sc_offset, self.rot_offset) |
|
|
|
|
|
# ----------------------- is_copy update ------------------------ |
|
def up_ui_is_copy(self): |
|
"""Update the value of the property is_copy in UI""" |
|
self.is_prog_change = True |
|
self.is_copy = False |
|
|
|
|
|
def update_is_copy(self, context): |
|
"""Allow a copy or duplicate(copy link by default)""" |
|
if self.is_prog_change: |
|
self.is_prog_change = False |
|
else: |
|
if self.is_copy: # no need to rebuild all |
|
for i in range(self.row): |
|
for j in range(self.count): |
|
if i == 0 and j == 0: |
|
continue |
|
ref_name = cfg.atools_objs[0][0] |
|
elem_name = cfg.atools_objs[i][j] |
|
bpy.data.objects[elem_name].data = bpy.data.objects[ref_name].data.copy() |
|
else: # since the value change (now duplicate), need to rebuild |
|
count = self.count |
|
row = self.row |
|
ref_name = cfg.atools_objs[0][0] |
|
array_col = bpy.data.collections.get(cfg.col_name) |
|
|
|
# DO NOT USE BLENDER CRASH WITH IT |
|
# self.at_del_all(False) |
|
|
|
bpy.ops.object.delete({"selected_objects": array_col.objects}) |
|
cfg.atools_objs.clear() |
|
cfg.atools_objs.append([ref_name]) |
|
|
|
ref_obj = bpy.data.objects[ref_name] |
|
for i in range(row): |
|
if i != 0: |
|
cfg.atools_objs.append([]) |
|
for j in range(count + i*self.alter): |
|
objcp = ref_obj.copy() |
|
array_col.objects.link(objcp) |
|
cfg.atools_objs[i].append(objcp.name) |
|
del objcp |
|
del ref_obj |
|
|
|
if self.is_tr_off_last: |
|
self.update_offset(bpy.context) |
|
else: |
|
self.update_global(bpy.context) |
|
|
|
print("Rebuild done!") |
|
|
|
# ----------------------- random part --------------------------- |
|
# --------------------------------------------------------------- |
|
def update_seed(self, context): |
|
if self.at_mode == 'ADV': |
|
sc_min = (self.sc_min_x, self.sc_min_y, self.sc_min_z) |
|
sc_max = (self.sc_max_x, self.sc_max_y, self.sc_max_z) |
|
at_random(self.at_seed, self.count, self.row, self.tr_min, self.tr_max, sc_min, |
|
sc_max, self.rot_min, self.rot_max, self.at_is_tr, self.at_is_sc, self.at_is_rot, |
|
self.sc_all, self.tr_offset, self.tr_second, self.sc_offset, self.sc_second, |
|
self.rot_offset, self.rot_second, self.at_pivot, self.alter, self.ralign) |
|
else: # simple mode |
|
vec = xyz_axis() |
|
tr = self.tr_rand * vec |
|
sc = self.sc_rand * vec |
|
rot = self.rot_rand * vec |
|
at_random(self.at_seed, self.count, self.row, -tr, tr, sc, 100*vec, -rot, rot, |
|
self.at_is_tr, self.at_is_sc, self.at_is_rot, False, self.tr_offset, |
|
self.tr_second, self.sc_offset, self.sc_second, self.rot_offset, |
|
self.rot_second, self.at_pivot, self.alter, self.ralign) |
|
|
|
|
|
def update_rtr(self, context): |
|
"""rtr in simple mode update adv mode""" |
|
self.tr_max = self.tr_rand * Vector((1.0, 1.0, 1.0)) |
|
self.tr_min = self.tr_rand * Vector((-1.0, -1.0, -1.0)) |
|
|
|
|
|
def update_rsc(self, context): |
|
"""rsc in simple mode update adv mode""" |
|
self.sc_max_x, self.sc_max_y, self.sc_max_z = (100.0, 100.0, 100.0) |
|
rand = self.sc_rand |
|
self.sc_min_x = rand |
|
self.sc_min_y = rand |
|
self.sc_min_z = rand |
|
|
|
|
|
def update_rrot(self, context): |
|
"""rrot in simple mode update adv mode""" |
|
self.rot_max = self.rot_rand * Vector((1.0, 1.0, 1.0)) |
|
self.rot_min = self.rot_rand * Vector((-1.0, -1.0, -1.0)) |
|
|
|
|
|
def up_ui_sc_min_x(self, val): |
|
"""Update the value of the property sc_min_x in UI""" |
|
self.is_prog_change = True |
|
self.sc_min_x = val |
|
|
|
|
|
def up_ui_sc_min_y(self, val): |
|
"""Update the value of the property sc_min_y in UI""" |
|
self.is_prog_change = True |
|
self.sc_min_y = val |
|
|
|
|
|
def up_ui_sc_min_z(self, val): |
|
"""Update the value of the property sc_min_z in UI""" |
|
self.is_prog_change = True |
|
self.sc_min_z = val |
|
|
|
|
|
def up_ui_sc_max_x(self, val): |
|
"""Update the value of the property sc_max_x in UI""" |
|
self.is_prog_change = True |
|
self.sc_max_x = val |
|
|
|
|
|
def up_ui_sc_max_y(self, val): |
|
"""Update the value of the property sc_max_y in UI""" |
|
self.is_prog_change = True |
|
self.sc_max_y = val |
|
|
|
|
|
def up_ui_sc_max_z(self, val): |
|
"""Update the value of the property sc_max_z in UI""" |
|
self.is_prog_change = True |
|
self.sc_max_z = val |
|
|
|
# -------------- update min and max ----------------------------- |
|
# if user enter a max value < min, change min and vice versa |
|
def up_tr_min(self, context): |
|
"""Update tr_max if tr_min is higher""" |
|
if self.is_prog_change: |
|
self.is_prog_change = False |
|
else: |
|
for i in range(3): |
|
if self.tr_min[i] > self.tr_max[i]: |
|
self.is_prog_change = True |
|
self.tr_max[i] = self.tr_min[i] |
|
|
|
|
|
def up_tr_max(self, context): |
|
"""Update tr_min if tr_max is lower""" |
|
if self.is_prog_change: |
|
self.is_prog_change = False |
|
else: |
|
for i in range(3): |
|
if self.tr_min[i] > self.tr_max[i]: |
|
self.is_prog_change = True |
|
self.tr_min[i] = self.tr_max[i] |
|
|
|
|
|
def up_sc_min_x(self, context): |
|
"""Update sc_max_x if sc_min_x is higher""" |
|
if self.is_prog_change: |
|
self.is_prog_change = False |
|
else: |
|
test = self.sc_min_x > self.sc_max_x |
|
if test and self.sc_all: |
|
# case : min > max and uniform = True |
|
self.up_ui_sc_max_x(self.sc_min_x) |
|
# with uniform : min_x = min_y = min_z same for max_ |
|
self.up_ui_sc_min_y(self.sc_min_x) |
|
self.up_ui_sc_min_z(self.sc_min_x) |
|
self.up_ui_sc_max_y(self.sc_min_x) |
|
self.up_ui_sc_max_z(self.sc_min_x) |
|
elif self.sc_all: |
|
# case : min < max and uniform = True |
|
self.up_ui_sc_min_y(self.sc_min_x) |
|
self.up_ui_sc_min_z(self.sc_min_x) |
|
self.up_ui_sc_max_y(self.sc_max_x) |
|
self.up_ui_sc_max_z(self.sc_max_x) |
|
elif test: |
|
# case : min > max and uniform = False |
|
self.up_ui_sc_max_x(self.sc_min_x) |
|
|
|
def up_sc_min_y(self, context): |
|
"""Update sc_max_y if sc_min_y is higher""" |
|
if self.is_prog_change: |
|
self.is_prog_change = False |
|
else: |
|
test = self.sc_min_y > self.sc_max_y |
|
if test and self.sc_all: |
|
# case : min > max and uniform = True |
|
self.up_ui_sc_max_y(self.sc_min_y) |
|
# with uniform : min_x = min_y = min_z same for max_ |
|
self.up_ui_sc_min_x(self.sc_min_y) |
|
self.up_ui_sc_min_z(self.sc_min_y) |
|
self.up_ui_sc_max_x(self.sc_min_y) |
|
self.up_ui_sc_max_y(self.sc_min_y) |
|
elif self.sc_all: |
|
# case : min < max and uniform = True |
|
self.up_ui_sc_min_x(self.sc_min_y) |
|
self.up_ui_sc_min_z(self.sc_min_y) |
|
self.up_ui_sc_max_x(self.sc_max_y) |
|
self.up_ui_sc_max_z(self.sc_max_y) |
|
elif test: |
|
# case : min > max and uniform = False |
|
self.up_ui_sc_max_y(self.sc_min_y) |
|
|
|
def up_sc_min_z(self, context): |
|
"""Update sc_max_z if sc_min_z is higher""" |
|
if self.is_prog_change: |
|
self.is_prog_change = False |
|
else: |
|
test = self.sc_min_z > self.sc_max_z |
|
if test and self.sc_all: |
|
# case : min > max and uniform = True |
|
self.up_ui_sc_max_z(self.sc_min_z) |
|
# with uniform : min_x = min_y = min_z same for max_ |
|
self.up_ui_sc_min_x(self.sc_min_z) |
|
self.up_ui_sc_min_y(self.sc_min_z) |
|
self.up_ui_sc_max_x(self.sc_min_z) |
|
self.up_ui_sc_max_y(self.sc_min_z) |
|
elif self.sc_all: |
|
# case : min < max and uniform = True |
|
self.up_ui_sc_min_x(self.sc_min_z) |
|
self.up_ui_sc_min_y(self.sc_min_z) |
|
self.up_ui_sc_max_x(self.sc_max_z) |
|
self.up_ui_sc_max_y(self.sc_max_z) |
|
elif test: |
|
# case : min > max and uniform = False |
|
self.up_ui_sc_max_y(self.sc_min_z) |
|
|
|
def up_sc_max_x(self, context): |
|
"""Update sc_min_x if sc_max_x is lower""" |
|
if self.is_prog_change: |
|
self.is_prog_change = False |
|
else: |
|
test = self.sc_min_x > self.sc_max_x |
|
if test and self.sc_all: |
|
# case : min > max and uniform = True |
|
self.up_ui_sc_min_x(self.sc_max_x) |
|
# with uniform : min_x = min_y = min_z same for max_ |
|
self.up_ui_sc_max_y(self.sc_max_x) |
|
self.up_ui_sc_max_z(self.sc_max_x) |
|
self.up_ui_sc_min_y(self.sc_max_x) |
|
self.up_ui_sc_min_z(self.sc_max_x) |
|
elif self.sc_all: |
|
# case : min < max and uniform = True |
|
self.up_ui_sc_max_y(self.sc_max_x) |
|
self.up_ui_sc_max_z(self.sc_max_x) |
|
self.up_ui_sc_min_y(self.sc_min_x) |
|
self.up_ui_sc_min_z(self.sc_min_x) |
|
elif test: |
|
# case : min > max and uniform = False |
|
self.up_ui_sc_min_x(self.sc_max_x) |
|
|
|
def up_sc_max_y(self, context): |
|
"""Update sc_min_y if sc_max_y is lower""" |
|
if self.is_prog_change: |
|
self.is_prog_change = False |
|
else: |
|
test = self.sc_min_y > self.sc_max_y |
|
if test and self.sc_all: |
|
# case : min > max and uniform = True |
|
self.up_ui_sc_min_y(self.sc_max_y) |
|
# with uniform : min_x = min_y = min_z same for max_ |
|
self.up_ui_sc_max_x(self.sc_max_y) |
|
self.up_ui_sc_max_z(self.sc_max_y) |
|
self.up_ui_sc_min_x(self.sc_max_y) |
|
self.up_ui_sc_min_z(self.sc_max_y) |
|
elif self.sc_all: |
|
# case : min < max and uniform = True |
|
self.up_ui_sc_max_x(self.sc_max_y) |
|
self.up_ui_sc_max_z(self.sc_max_y) |
|
self.up_ui_sc_min_x(self.sc_min_y) |
|
self.up_ui_sc_min_z(self.sc_min_y) |
|
elif test: |
|
# case : min > max and uniform = False |
|
self.up_ui_sc_min_y(self.sc_max_y) |
|
|
|
def up_sc_max_z(self, context): |
|
"""Update sc_min_z if sc_max_z is lower""" |
|
if self.is_prog_change: |
|
self.is_prog_change = False |
|
else: |
|
test = self.sc_min_z > self.sc_max_z |
|
if test and self.sc_all: |
|
# case : min > max and uniform = True |
|
self.up_ui_sc_min_z(self.sc_max_z) |
|
# with uniform : min_x = min_y = min_z same for max_ |
|
self.up_ui_sc_max_x(self.sc_max_z) |
|
self.up_ui_sc_max_y(self.sc_max_z) |
|
self.up_ui_sc_min_x(self.sc_max_z) |
|
self.up_ui_sc_min_y(self.sc_max_z) |
|
elif self.sc_all: |
|
# case : min < max and uniform = True |
|
self.up_ui_sc_max_x(self.sc_max_z) |
|
self.up_ui_sc_max_y(self.sc_max_z) |
|
self.up_ui_sc_min_x(self.sc_min_z) |
|
self.up_ui_sc_min_y(self.sc_min_z) |
|
elif test: |
|
# case : min > max and uniform = False |
|
self.up_ui_sc_min_z(self.sc_max_z) |
|
|
|
def up_rot_min(self, context): |
|
"""Update rot_max if rot_min is higher""" |
|
if self.is_prog_change: |
|
self.is_prog_change = False |
|
else: |
|
for i in range(3): |
|
if self.rot_min[i] > self.rot_max[i]: |
|
self.is_prog_change = True |
|
self.rot_max[i] = self.rot_min[i] |
|
|
|
def up_rot_max(self, context): |
|
"""Update rot_min if rot_max is lower""" |
|
if self.is_prog_change: |
|
self.is_prog_change = False |
|
else: |
|
for i in range(3): |
|
if self.rot_min[i] > self.rot_max[i]: |
|
self.is_prog_change = True |
|
self.rot_min[i] = self.rot_max[i] |
|
|
|
# ----------------------- reset all properties ------------------ |
|
def up_ui_reset(self): |
|
"""Reset all UI properties""" |
|
self.up_ui_updateCount(2) |
|
self.up_ui_updateRow(1) |
|
self.up_ui_is_copy() |
|
self.up_ui_tr_offset(Vector((2.0, 0.0, 0.0))) |
|
self.up_ui_tr_global(Vector((2.0, 0.0, 0.0))) |
|
self.up_ui_sc_offset((100, 100, 100)) |
|
self.up_ui_sc_global((100, 100, 100)) |
|
self.up_ui_rot_offset(Vector((0.0, 0.0, 0.0))) |
|
self.up_ui_rot_global(Vector((0.0, 0.0, 0.0))) |
|
self.up_ui_updateAlter(0) |
|
self.total = "2" |
|
self.erow = "2" |
|
|
|
|
|
count: bpy.props.IntProperty( |
|
name='Count', |
|
description="Number of elements, original count as one", |
|
default=2, |
|
soft_min=2, |
|
update=updateCount |
|
) |
|
|
|
row: bpy.props.IntProperty( |
|
name="Row", |
|
description="Number of row(s)", |
|
default=1, |
|
soft_min=1, |
|
soft_max=100, |
|
update=update_row |
|
) |
|
|
|
"""Allow a variation in the row : |
|
if row gets n elements, row +1 will get (n + variation) elements |
|
only if n + variation > 0 |
|
""" |
|
alter: bpy.props.IntProperty( |
|
name=" Row variation", |
|
description="""Variation in the number of elements in a row. (between -5 and 5). |
|
\n Be careful with it""", |
|
default=0, |
|
soft_min=-5, |
|
soft_max=5, |
|
update=update_alter |
|
) |
|
|
|
total: bpy.props.StringProperty( |
|
name="Total", |
|
description="Total of elements in array", |
|
default="2" |
|
) |
|
|
|
erow: bpy.props.StringProperty( |
|
description="Number of elements in the current row.", |
|
default="2" |
|
) |
|
|
|
# if alter <> 0, how align the rows |
|
align: bpy.props.EnumProperty( |
|
name='Align', |
|
description="Align of rows when variation is not zero", |
|
items=[ |
|
('LEFT', 'Left', "Align to the left", 'ALIGN_LEFT', 0), |
|
('CENTER', 'Center', "Align to the center", 'ALIGN_CENTER', 1), |
|
('RIGHT', 'Right', "Align to the right", 'ALIGN_RIGHT', 2) |
|
], |
|
default='LEFT', |
|
update=update_align |
|
) |
|
|
|
# Vector alignment depends on align |
|
ralign: bpy.props.FloatVectorProperty( |
|
subtype='TRANSLATION', |
|
unit='LENGTH', |
|
default=(0.0, 0.0, 0.0) |
|
) |
|
|
|
# booleans use to know if user or prog change the value to avoid continuous loop |
|
is_prog_change: bpy.props.BoolProperty(default=False) # True if prog change value |
|
|
|
# which one between offset and global user calls last, True is offset, False global |
|
is_tr_off_last: bpy.props.BoolProperty(default=True) |
|
|
|
# True if addon is initialised |
|
already_start: bpy.props.BoolProperty(default=False) |
|
|
|
# if the user need a single copy or a duplicate (link object) |
|
is_copy: bpy.props.BoolProperty( |
|
name="Copy only", |
|
description="Duplicate or copy, default is duplicate", |
|
default=False, |
|
update=update_is_copy |
|
) |
|
|
|
# translation vector offset |
|
tr_offset: bpy.props.FloatVectorProperty( |
|
name='Offset', |
|
description="Distance between elements", |
|
default=(2.0, 0.0, 0.0), |
|
subtype='TRANSLATION', |
|
unit='LENGTH', |
|
precision=2, |
|
step=50, |
|
options={'ANIMATABLE'}, |
|
update=update_offset |
|
) |
|
|
|
# global translation distance |
|
tr_global: bpy.props.FloatVectorProperty( |
|
name='Global', |
|
description="Distance between the original and the last element", |
|
default=(2.0, 0.0, 0.0), |
|
subtype='TRANSLATION', |
|
unit='LENGTH', |
|
precision=2, |
|
step=50, |
|
options={'ANIMATABLE'}, |
|
update=update_global |
|
) |
|
|
|
tr_second: bpy.props.FloatVectorProperty( |
|
name="Translation", |
|
description="Additional offset distance for rows", |
|
default=(0.0, 0.0, 0.0), |
|
subtype='TRANSLATION', |
|
unit='LENGTH', |
|
precision=2, |
|
step=50, |
|
update=update_second |
|
) |
|
|
|
at_pivot: bpy.props.PointerProperty( |
|
name='Pivot', |
|
description="Object you want as pivot point. If none, pivot point is the object's origine", |
|
type=bpy.types.Object |
|
) |
|
|
|
# scaling vector offset |
|
sc_offset: bpy.props.FloatVectorProperty( |
|
name='Offset', |
|
description="Incremental scale of the next elements", |
|
default=(100.0, 100.0, 100.0), |
|
subtype='XYZ', |
|
precision=1, |
|
step=100, |
|
options={'ANIMATABLE'}, |
|
update=update_offset |
|
) |
|
|
|
# global scaling |
|
sc_global: bpy.props.FloatVectorProperty( |
|
name='Global', |
|
description="Scale of the last element", |
|
default=(100.0, 100.0, 100.0), |
|
subtype='XYZ', |
|
precision=1, |
|
step=100, |
|
options={'ANIMATABLE'}, |
|
update=update_global |
|
) |
|
|
|
sc_second: bpy.props.FloatVectorProperty( |
|
name='Scale', |
|
description="Additionnal scale for rows", |
|
default=(100.0, 100.0, 100.0), |
|
subtype='XYZ', |
|
precision=1, |
|
step=100, |
|
options={'ANIMATABLE'}, |
|
update=update_second |
|
) |
|
# rotation vector offset |
|
rot_offset: bpy.props.FloatVectorProperty( |
|
name='Offset', |
|
description="Angle between each element", |
|
default=(0.0, 0.0, 0.0), |
|
subtype='XYZ', |
|
unit='ROTATION', |
|
step=500, # = 5 |
|
options={'ANIMATABLE'}, |
|
update=update_offset |
|
) |
|
|
|
# global rotation |
|
rot_global: bpy.props.FloatVectorProperty( |
|
name='Global', |
|
description="Maximum angle from the reference to the last element", |
|
default=(0.0, 0.0, 0.0), |
|
subtype='XYZ', |
|
unit='ROTATION', |
|
step=500, # = 5 |
|
options={'ANIMATABLE'}, |
|
update=update_global |
|
) |
|
|
|
rot_second: bpy.props.FloatVectorProperty( |
|
name='Rotation', |
|
description="Additionnal rotation for rows", |
|
default=(0.0, 0.0, 0.0), |
|
subtype='XYZ', |
|
unit='ROTATION', |
|
step=500, |
|
options={'ANIMATABLE'}, |
|
update=update_second |
|
) |
|
|
|
# ----------------------- random part --------------------------- |
|
at_seed: bpy.props.IntProperty( |
|
name='Seed', |
|
description="Seed value for random", |
|
soft_min=0, |
|
default=0, |
|
update=update_seed |
|
) |
|
|
|
at_mode: bpy.props.EnumProperty( |
|
name="Mode", |
|
description="Choose between simple mode or advanced", |
|
items=(('SIM', 'Simple', "Simple mode"), |
|
('ADV', 'Advanced', "Advanced mode")), |
|
default='SIM' |
|
) |
|
|
|
at_is_tr: bpy.props.BoolProperty( |
|
name="Add translation", |
|
description="Add translation in random?", |
|
default=False |
|
) |
|
|
|
at_is_sc: bpy.props.BoolProperty( |
|
name="Add scale", |
|
description="Add scale in random?", |
|
default=False |
|
) |
|
|
|
at_is_rot: bpy.props.BoolProperty( |
|
name="Add rotation", |
|
description="Add rotation in random?", |
|
default=False |
|
) |
|
|
|
tr_min: bpy.props.FloatVectorProperty( |
|
name="min", |
|
description="Minimum random value for translation", |
|
unit='LENGTH', |
|
default=(0.0, 0.0, 0.0), |
|
update=up_tr_min |
|
) |
|
|
|
tr_max: bpy.props.FloatVectorProperty( |
|
name="max", |
|
description="Maximum random value for translation", |
|
unit='LENGTH', |
|
default=(0.0, 0.0, 0.0), |
|
update=up_tr_max |
|
) |
|
|
|
tr_rand: bpy.props.FloatProperty( |
|
name="Translation", |
|
description="Random values for all axis", |
|
unit='LENGTH', |
|
default=0.0, |
|
update=update_rtr |
|
) |
|
|
|
sc_all: bpy.props.BoolProperty( |
|
name="uniform scale", |
|
description="Uniform or non uniform scale, default is non uniform.", |
|
default=False |
|
) |
|
|
|
sc_min_x: bpy.props.IntProperty( |
|
name="min", |
|
description="Minimum random value for x scale", |
|
default=100, |
|
update=up_sc_min_x |
|
) |
|
|
|
sc_min_y: bpy.props.IntProperty( |
|
name="min", |
|
description="Minimum random value for y scale", |
|
default=100, |
|
update=up_sc_min_y |
|
) |
|
|
|
sc_min_z: bpy.props.IntProperty( |
|
name="min", |
|
description="Minimum random value for z scale", |
|
default=100, |
|
update=up_sc_min_z |
|
) |
|
|
|
sc_max_x: bpy.props.IntProperty( |
|
name="max", |
|
description="Maximum random value for x scale", |
|
default=100, |
|
update=up_sc_max_x |
|
) |
|
|
|
sc_max_y: bpy.props.IntProperty( |
|
name="max", |
|
description="Maximum random value for y scale", |
|
default=100, |
|
update=up_sc_max_y |
|
) |
|
|
|
sc_max_z: bpy.props.IntProperty( |
|
name="max", |
|
description="Maximum random value for z scale", |
|
default=100, |
|
update=up_sc_max_z |
|
) |
|
|
|
sc_rand: bpy.props.IntProperty( |
|
name="Scale", |
|
description="Random scale value for all axis", |
|
default=100, |
|
update=update_rsc |
|
) |
|
|
|
rot_min: bpy.props.FloatVectorProperty( |
|
name="min", |
|
description="Minimum random value for rotation", |
|
unit='ROTATION', |
|
default=(0.0, 0.0, 0.0), |
|
update=up_rot_min |
|
) |
|
|
|
rot_max: bpy.props.FloatVectorProperty( |
|
name="max", |
|
description="Maximum random value for rotation", |
|
unit='ROTATION', |
|
default=(0.0, 0.0, 0.0), |
|
update=up_rot_max |
|
) |
|
|
|
rot_rand: bpy.props.FloatProperty( |
|
name="Rotation", |
|
description="Random rotation for all axis", |
|
unit='ROTATION', |
|
default=0.0, |
|
update=update_rrot |
|
)
|
|
|