1224 lines
44 KiB
Plaintext
1224 lines
44 KiB
Plaintext
|
# -*- 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
|
||
|
)
|