-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathproperties.py
More file actions
232 lines (199 loc) · 9.13 KB
/
properties.py
File metadata and controls
232 lines (199 loc) · 9.13 KB
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
"""
Properties - Centralized property definitions for the Pivotier addon.
All PropertyGroups are defined here and aggregated under PivotierProperties,
which is registered on WindowManager so the state is global (not per-scene)
and does not appear in scene datablocks.
"""
import bpy
import math
# ─── Existing property groups ─────────────────────────────────────────────────
class SetPivotToBaseProperties(bpy.types.PropertyGroup):
"""Options for the Set Pivot to Base operator."""
ignore_rotation: bpy.props.BoolProperty(
name="Ignore Object Rotation",
description=(
"Calculate the base point as if the object had no rotation. "
"Useful for objects that have been rotated but not applied"
),
default=False,
)
use_lowest_vertex: bpy.props.BoolProperty(
name="Use Lowest Vertex",
description="Set pivot to the lowest single vertex instead of the bounding box center",
default=False,
)
class BatchAlignmentProperties(bpy.types.PropertyGroup):
"""Settings for the Batch Align Objects operator."""
align_x: bpy.props.BoolProperty(name="X", description="Align along X axis", default=True)
align_y: bpy.props.BoolProperty(name="Y", description="Align along Y axis", default=True)
align_z: bpy.props.BoolProperty(name="Z", description="Align along Z axis", default=True)
relative_to: bpy.props.EnumProperty(
name="Relative To",
description="Reference point for alignment",
items=[
('ACTIVE', "Active Object", "Use the active object as reference"),
('CURSOR', "3D Cursor", "Use the 3D cursor as reference"),
('WORLD', "World Origin", "Use the world origin (0, 0, 0)"),
('AVERAGE', "Selection Average", "Use the average position of all selected objects"),
],
default='ACTIVE',
)
align_mode: bpy.props.EnumProperty(
name="Align Mode",
description="What transform component to align",
items=[
('LOCATION', "Location", "Align object locations only"),
('ROTATION', "Rotation", "Align object rotations only"),
('BOTH', "Both", "Align both location and rotation"),
],
default='BOTH',
)
# ─── New property groups ──────────────────────────────────────────────────────
class DropToSurfaceProperties(bpy.types.PropertyGroup):
"""Options for the Drop to Surface operator."""
axis: bpy.props.EnumProperty(
name="Drop Axis",
description="Direction to project the object onto the surface",
items=[
('NEG_Z', "-Z (Down)", "Drop along negative Z — gravity direction"),
('POS_Z', "+Z (Up)", "Drop along positive Z"),
('NEG_X', "-X", "Drop along negative X"),
('POS_X', "+X", "Drop along positive X"),
('NEG_Y', "-Y", "Drop along negative Y"),
('POS_Y', "+Y", "Drop along positive Y"),
],
default='NEG_Z',
)
align_to_normal: bpy.props.BoolProperty(
name="Align to Normal",
description=(
"Rotate each object so its +Z axis aligns with the surface normal "
"at the landing point"
),
default=False,
)
class AlignToCameraProperties(bpy.types.PropertyGroup):
"""Options for the Align to Camera (billboard) operator."""
track_axis: bpy.props.EnumProperty(
name="Track Axis",
description="Object-space axis that will point toward the camera",
items=[
('-Y', "-Y (Default forward)", "Object's -Y axis faces the camera (Blender's default forward)"),
('Y', "+Y", "Object's +Y axis faces the camera"),
('-Z', "-Z", "Object's -Z axis faces the camera"),
('Z', "+Z", "Object's +Z axis faces the camera"),
('-X', "-X", "Object's -X axis faces the camera"),
('X', "+X", "Object's +X axis faces the camera"),
],
default='-Y',
)
class RandomizeProperties(bpy.types.PropertyGroup):
"""Options for the Randomize Transforms operator."""
seed: bpy.props.IntProperty(
name="Seed",
description="Random seed — identical seed always gives the same result",
default=0,
min=0,
max=99999,
)
# ── Location ──────────────────────────────────────────────────────────────
use_location: bpy.props.BoolProperty(
name="Location",
description="Add random offset to object locations",
default=True,
)
loc_min: bpy.props.FloatVectorProperty(
name="Min",
description="Minimum random location offset per axis (X, Y, Z)",
size=3,
default=(-0.5, -0.5, 0.0),
subtype='XYZ',
)
loc_max: bpy.props.FloatVectorProperty(
name="Max",
description="Maximum random location offset per axis (X, Y, Z)",
size=3,
default=(0.5, 0.5, 0.0),
subtype='XYZ',
)
# ── Rotation ──────────────────────────────────────────────────────────────
use_rotation: bpy.props.BoolProperty(
name="Rotation",
description="Add random offset to object rotations",
default=True,
)
rot_min: bpy.props.FloatVectorProperty(
name="Min",
description="Minimum random rotation offset per axis",
size=3,
default=(0.0, 0.0, -math.pi),
subtype='EULER',
unit='ROTATION',
)
rot_max: bpy.props.FloatVectorProperty(
name="Max",
description="Maximum random rotation offset per axis",
size=3,
default=(0.0, 0.0, math.pi),
subtype='EULER',
unit='ROTATION',
)
# ── Scale ─────────────────────────────────────────────────────────────────
use_scale: bpy.props.BoolProperty(
name="Scale",
description="Multiply object scale by a random factor",
default=False,
)
uniform_scale: bpy.props.BoolProperty(
name="Uniform Scale",
description="Apply the same random factor to all three axes",
default=True,
)
scale_min: bpy.props.FloatProperty(
name="Min",
description="Minimum scale multiplier",
default=0.8,
min=0.001,
soft_max=2.0,
)
scale_max: bpy.props.FloatProperty(
name="Max",
description="Maximum scale multiplier",
default=1.2,
min=0.001,
soft_max=2.0,
)
# ─── Master container ─────────────────────────────────────────────────────────
class PivotierProperties(bpy.types.PropertyGroup):
"""Root property group registered on WindowManager."""
# Operator sub-groups
pivot_to_base: bpy.props.PointerProperty(type=SetPivotToBaseProperties)
batch_align: bpy.props.PointerProperty(type=BatchAlignmentProperties)
drop_to_surface: bpy.props.PointerProperty(type=DropToSurfaceProperties)
align_to_camera: bpy.props.PointerProperty(type=AlignToCameraProperties)
randomize: bpy.props.PointerProperty(type=RandomizeProperties)
# UI state: collapsible panel sections (persist per session via WindowManager)
show_set_dressing: bpy.props.BoolProperty(name="Set Dressing", default=True)
show_batch_alignment: bpy.props.BoolProperty(name="Batch Alignment", default=True)
show_distribute: bpy.props.BoolProperty(name="Distribute", default=True)
show_randomize: bpy.props.BoolProperty(name="Randomize", default=True)
show_pivot_point: bpy.props.BoolProperty(name="Pivot Point", default=True)
show_cursor_alignment: bpy.props.BoolProperty(name="Cursor Alignment", default=True)
show_bookmarks: bpy.props.BoolProperty(name="Cursor Bookmarks", default=True)
# ─── Registration ─────────────────────────────────────────────────────────────
classes = (
SetPivotToBaseProperties,
BatchAlignmentProperties,
DropToSurfaceProperties,
AlignToCameraProperties,
RandomizeProperties,
PivotierProperties,
)
def register():
for cls in classes:
bpy.utils.register_class(cls)
bpy.types.WindowManager.pivotier = bpy.props.PointerProperty(type=PivotierProperties)
def unregister():
del bpy.types.WindowManager.pivotier
for cls in reversed(classes):
bpy.utils.unregister_class(cls)