Fix T52833: OBJ triangulate doesn't match viewport
[blender-addons.git] / add_advanced_objects_menu / random_box_structure.py
blobfa4b6497f6c8f059e5ffd2c3ff87032d8a9d2d12
1 # gpl: author Dannyboy
3 bl_info = {
4 "name": "Add Random Box Structure",
5 "author": "Dannyboy",
6 "version": (1, 0, 1),
7 "location": "View3D > Add > Make Box Structure",
8 "description": "Fill selected box shaped meshes with randomly sized cubes",
9 "warning": "",
10 "wiki_url": "",
11 "tracker_url": "dannyboypython.blogspot.com",
12 "category": "Object"}
14 import bpy
15 import random
16 from bpy.types import Operator
17 from bpy.props import (
18 BoolProperty,
19 FloatProperty,
20 FloatVectorProperty,
21 IntProperty,
25 class makestructure(Operator):
26 bl_idname = "object.make_structure"
27 bl_label = "Add Random Box Structure"
28 bl_description = ("Create a randomized structure made of boxes\n"
29 "with various control parameters\n"
30 "Needs an existing Active Mesh Object")
31 bl_options = {'REGISTER', 'UNDO'}
33 dc = BoolProperty(
34 name="Delete Base Mesh(es)",
35 default=True
37 wh = BoolProperty(
38 name="Stay Within Bounds",
39 description="Keeps cubes from exceeding base mesh bounds",
40 default=True
42 uf = BoolProperty(
43 name="Uniform Cube Quantity",
44 default=False
46 qn = IntProperty(
47 name="Cube Quantity",
48 default=10,
49 min=1, max=1500
51 mn = FloatVectorProperty(
52 name="Min Scales",
53 default=(0.1, 0.1, 0.1),
54 subtype='XYZ'
56 mx = FloatVectorProperty(
57 name="Max Scales",
58 default=(2.0, 2.0, 2.0),
59 subtype='XYZ'
61 lo = FloatVectorProperty(
62 name="XYZ Offset",
63 default=(0.0, 0.0, 0.0),
64 subtype='XYZ'
66 rsd = FloatProperty(
67 name="Random Seed",
68 default=1
71 @classmethod
72 def poll(cls, context):
73 obj = context.active_object
74 return obj is not None and obj.type == "MESH" and obj.mode == "OBJECT"
76 def draw(self, context):
77 layout = self.layout
79 box = layout.box()
80 box.label(text="Options:")
81 box.prop(self, "dc")
82 box.prop(self, "wh")
83 box.prop(self, "uf")
85 box = layout.box()
86 box.label(text="Parameters:")
87 box.prop(self, "qn")
88 box.prop(self, "mn")
89 box.prop(self, "mx")
90 box.prop(self, "lo")
91 box.prop(self, "rsd")
93 def execute(self, context):
94 rsdchange = self.rsd
95 oblst = []
96 uvyes = 0
97 bpy.ops.group.create(name='Cubagrouper')
98 bpy.ops.group.objects_remove()
100 for ob in bpy.context.selected_objects:
101 oblst.append(ob)
103 for obj in oblst:
104 bpy.ops.object.select_pattern(pattern=obj.name) # Select base mesh
105 bpy.context.scene.objects.active = obj
106 if obj.data.uv_layers[:] != []:
107 uvyes = 1
108 else:
109 uvyes = 0
110 bpy.ops.object.group_link(group='Cubagrouper')
111 dim = obj.dimensions
112 rot = obj.rotation_euler
113 if self.uf is True:
114 area = dim.x * dim.y * dim.z
115 else:
116 area = 75
118 for cube in range(round((area / 75) * self.qn)):
119 random.seed(rsdchange)
120 pmn = self.mn # Proxy values
121 pmx = self.mx
122 if self.wh is True:
123 if dim.x < pmx.x: # Keeping things from exceeding proper size
124 pmx.x = dim.x
125 if dim.y < pmx.y:
126 pmx.y = dim.y
127 if dim.z < pmx.z:
128 pmx.z = dim.z
129 if 0.0 > pmn.x: # Keeping things from going under zero
130 pmn.x = 0.0
131 if 0.0 > pmn.y:
132 pmn.y = 0.0
133 if 0.0 > pmn.z:
134 pmn.z = 0.0
135 sx = (random.random() * (pmx.x - pmn.x)) + pmn.x # Just changed self.mx and .mn to pmx.
136 sy = (random.random() * (pmx.y - pmn.y)) + pmn.y
137 sz = (random.random() * (pmx.z - pmn.z)) + pmn.z
138 if self.wh is True: # This keeps the cubes within the base mesh
139 ex = (random.random() * (dim.x - sx)) - ((dim.x - sx) / 2) + obj.location.x
140 wy = (random.random() * (dim.y - sy)) - ((dim.y - sy) / 2) + obj.location.y
141 ze = (random.random() * (dim.z - sz)) - ((dim.z - sz) / 2) + obj.location.z
142 elif self.wh is False:
143 ex = (random.random() * dim.x) - (dim.x / 2) + obj.location.x
144 wy = (random.random() * dim.y) - (dim.y / 2) + obj.location.y
145 ze = (random.random() * dim.z) - (dim.z / 2) + obj.location.z
146 bpy.ops.mesh.primitive_cube_add(
147 radius=0.5, location=(ex + self.lo.x, wy + self.lo.y, ze + self.lo.z)
149 bpy.ops.object.mode_set(mode='EDIT')
150 bpy.ops.mesh.select_all(action='SELECT')
151 bpy.ops.transform.resize(
152 value=(sx, sy, sz), constraint_axis=(True, True, True),
153 constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED',
154 proportional_edit_falloff='SMOOTH', proportional_size=1, release_confirm=True
156 bpy.ops.object.mode_set(mode='OBJECT')
157 select = bpy.context.object # This is used to keep something selected for poll()
158 bpy.ops.object.group_link(group='Cubagrouper')
159 rsdchange += 3
160 bpy.ops.object.select_grouped(type='GROUP')
161 bpy.ops.transform.rotate(
162 value=rot[0], axis=(1, 0, 0), constraint_axis=(False, False, False),
163 constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED',
164 proportional_edit_falloff='SMOOTH', proportional_size=1, release_confirm=True
166 bpy.ops.transform.rotate(
167 value=rot[1], axis=(0, 1, 0), constraint_axis=(False, False, False),
168 constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED',
169 proportional_edit_falloff='SMOOTH', proportional_size=1, release_confirm=True
171 bpy.ops.transform.rotate(
172 value=rot[2], axis=(0, 0, 1), constraint_axis=(False, False, False),
173 constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED',
174 proportional_edit_falloff='SMOOTH', proportional_size=1, release_confirm=True
176 bpy.context.scene.objects.active = obj # Again needed to avoid poll() taking me down
177 bpy.ops.object.make_links_data(type='MODIFIERS')
178 bpy.ops.object.make_links_data(type='MATERIAL')
180 if uvyes == 1:
181 bpy.ops.object.join_uvs()
183 bpy.ops.group.objects_remove()
184 bpy.context.scene.objects.active = select
186 if self.dc is True:
187 bpy.context.scene.objects.unlink(obj)
189 return {'FINISHED'}
192 def register():
193 bpy.utils.register_class(makestructure)
196 def unregister():
197 bpy.utils.unregister_class(makestructure)
200 if __name__ == "__main__":
201 register()