4 "name": "Arrange on Curve",
8 "location": "3D View > Toolshelf > Create > Arrange on Curve",
9 "description": "Arrange objects along a curve",
10 "warning": "Select curve",
15 # Note: scene properties are moved into __init__
16 # search for patterns advanced_objects and adv_obj
20 from bpy
.types
import (
24 from bpy
.props
import (
33 class PanelDupliCurve(Panel
):
34 bl_idname
= "VIEW3D_PT_arranjar_numa_curva"
35 bl_space_type
= "VIEW_3D"
36 bl_region_type
= "TOOLS"
37 bl_context
= "objectmode"
38 bl_category
= "Create"
39 bl_label
= "Arrange on Curve"
40 bl_options
= {'DEFAULT_CLOSED'}
43 def poll(cls
, context
):
44 return context
.object and context
.mode
== 'OBJECT' and context
.object.type == 'CURVE'
46 def draw(self
, context
):
48 adv_obj
= context
.scene
.advanced_objects
50 layout
.prop(adv_obj
, "arrange_c_use_selected")
52 if not adv_obj
.arrange_c_use_selected
:
53 layout
.prop(adv_obj
, "arrange_c_select_type", expand
=True)
54 if adv_obj
.arrange_c_select_type
== 'O':
55 layout
.column(align
=True).prop_search(
56 adv_obj
, "arrange_c_obj_arranjar",
59 elif adv_obj
.arrange_c_select_type
== 'G':
60 layout
.column(align
=True).prop_search(
61 adv_obj
, "arrange_c_obj_arranjar",
64 if context
.object.type == 'CURVE':
65 layout
.operator("object.arranjar_numa_curva", text
="Arrange Objects")
68 class DupliCurve(Operator
):
69 bl_idname
= "object.arranjar_numa_curva"
70 bl_label
= "Arrange Objects along a Curve"
71 bl_description
= "Arange chosen / selected objects along the Active Curve"
72 bl_options
= {'REGISTER', 'UNDO'}
74 use_distance
= EnumProperty(
77 ("D", "Distance", "Objects are arranged depending on the distance", 0),
78 ("Q", "Quantity", "Objects are arranged depending on the quantity", 1),
79 ("R", "Range", "Objects are arranged uniformly between the corners", 2)
82 distance
= FloatProperty(
84 description
="Distance between Objects",
90 object_qt
= IntProperty(
92 description
="Object amount",
96 scale
= FloatProperty(
98 description
="Object Scale",
105 description
="Rotate around the X axis (Yaw)",
109 Pitch
= FloatProperty(
111 description
="Rotate around the Y axis (Pitch)",
115 Roll
= FloatProperty(
117 description
="Rotate around the Z axis (Roll)",
121 max_angle
= FloatProperty(
127 offset
= FloatProperty(
134 def poll(cls
, context
):
135 return context
.mode
== 'OBJECT'
137 def draw(self
, context
):
139 col
= layout
.column()
140 col
.prop(self
, "use_distance", text
="")
141 col
= layout
.column(align
=True)
142 if self
.use_distance
== "D":
143 col
.prop(self
, "distance")
144 elif self
.use_distance
== "Q":
145 col
.prop(self
, "object_qt")
147 col
.prop(self
, "distance")
148 col
.prop(self
, "max_angle")
149 col
.prop(self
, "offset")
151 col
= layout
.column(align
=True)
152 col
.prop(self
, "scale")
153 col
.prop(self
, "Yaw")
154 col
.prop(self
, "Pitch")
155 col
.prop(self
, "Roll")
157 def Glpoints(self
, curve
):
159 for i
, spline
in enumerate(curve
.data
.splines
):
160 segments
= len(spline
.bezier_points
)
162 r
= spline
.resolution_u
+ 1
165 for j
in range(segments
):
166 bp1
= spline
.bezier_points
[j
]
168 if inext
== segments
:
169 if not spline
.use_cyclic_u
:
172 bp2
= spline
.bezier_points
[inext
]
173 if bp1
.handle_right_type
== bp2
.handle_left_type
== 'VECTOR':
174 _points
= (bp1
.co
, bp2
.co
) if j
== 0 else (bp2
.co
,)
177 handle1
= bp1
.handle_right
178 handle2
= bp2
.handle_left
180 _points
= mathutils
.geometry
.interpolate_bezier(knot1
, handle1
, handle2
, knot2
, r
)
181 points
.extend(_points
)
182 Gpoints
.append(tuple((curve
.matrix_world
* p
for p
in points
)))
183 elif len(spline
.points
) >= 2:
184 l
= [curve
.matrix_world
* p
.co
.xyz
for p
in spline
.points
]
185 if spline
.use_cyclic_u
:
187 Gpoints
.append(tuple(l
))
189 if self
.use_distance
== "R":
190 max_angle
= self
.max_angle
199 if (3.14158 - v1
.angle(v2
)) < max_angle
:
200 tmp_Gpoints
.append(tuple(sp2
))
202 except Exception as e
:
203 print("\n[Add Advanced Objects]\nOperator: "
204 "object.arranjar_numa_curva\nError: {}".format(e
))
209 tmp_Gpoints
.append(tuple(sp2
))
210 Gpoints
= Gpoints
[:i
] + tmp_Gpoints
213 if self
.use_distance
!= "D":
216 leng
= (lp
- sp
[0]).length
218 leng
+= (p
- lp
).length
221 return Gpoints
, lengths
223 def execute(self
, context
):
224 if context
.object.type != 'CURVE':
227 curve
= context
.active_object
228 Gpoints
, lengs
= self
.Glpoints(curve
)
229 adv_obj
= context
.scene
.advanced_objects
231 if adv_obj
.arrange_c_use_selected
:
232 G_Objeto
= context
.selected_objects
233 G_Objeto
.remove(curve
)
238 elif adv_obj
.arrange_c_select_type
== 'O':
239 G_Objeto
= bpy
.data
.objects
[adv_obj
.arrange_c_obj_arranjar
],
240 elif adv_obj
.arrange_c_select_type
== 'G':
241 G_Objeto
= bpy
.data
.groups
[adv_obj
.arrange_c_obj_arranjar
].objects
243 yawMatrix
= mathutils
.Matrix
.Rotation(self
.Yaw
, 4, 'X')
244 pitchMatrix
= mathutils
.Matrix
.Rotation(self
.Pitch
, 4, 'Y')
245 rollMatrix
= mathutils
.Matrix
.Rotation(self
.Roll
, 4, 'Z')
247 max_angle
= self
.max_angle
# max_angle is called in Glpoints
249 if self
.use_distance
== "D":
251 for sp_points
in Gpoints
:
252 dx
= 0.0 # Length of initial calculation of section
253 last_point
= sp_points
[0]
255 for point
in sp_points
[1:]:
256 vetorx
= point
- last_point
# Vector spline section
257 quat
= mathutils
.Vector
.to_track_quat(vetorx
, 'X', 'Z') # Tracking the selected objects
258 quat
= quat
.to_matrix().to_4x4()
260 v_len
= vetorx
.length
262 dx
+= v_len
# Defined length calculation equal total length of the spline section
263 v_norm
= vetorx
/ v_len
265 object = G_Objeto
[j
% len(G_Objeto
)]
267 dx
-= dist
# Calculating the remaining length of the section
269 context
.scene
.objects
.link(obj
)
270 obj
.matrix_world
= quat
* yawMatrix
* pitchMatrix
* rollMatrix
271 # Placing in the correct position
272 obj
.matrix_world
.translation
= point
- v_norm
* dx
273 obj
.scale
*= self
.scale
276 elif self
.use_distance
== "Q":
277 object_qt
= self
.object_qt
+ 1
278 for i
, sp_points
in enumerate(Gpoints
):
279 dx
= 0.0 # Length of initial calculation of section
280 dist
= lengs
[i
] / object_qt
281 last_point
= sp_points
[0]
283 for point
in sp_points
[1:]:
284 vetorx
= point
- last_point
# Vector spline section
285 # Tracking the selected objects
286 quat
= mathutils
.Vector
.to_track_quat(vetorx
, 'X', 'Z')
287 quat
= quat
.to_matrix().to_4x4()
289 v_len
= vetorx
.length
291 # Defined length calculation equal total length of the spline section
293 v_norm
= vetorx
/ v_len
295 object = G_Objeto
[j
% len(G_Objeto
)]
297 dx
-= dist
# Calculating the remaining length of the section
299 context
.scene
.objects
.link(obj
)
300 obj
.matrix_world
= quat
* yawMatrix
* pitchMatrix
* rollMatrix
301 # Placing in the correct position
302 obj
.matrix_world
.translation
= point
- v_norm
* dx
303 obj
.scale
*= self
.scale
308 offset2
= 2 * self
.offset
309 for i
, sp_points
in enumerate(Gpoints
):
310 leng
= lengs
[i
] - offset2
312 offset
= offset2
+ rest
315 last_point
= sp_points
[0]
317 dx
= dist
- offset
# Length of initial calculation of section
319 for point
in sp_points
[1:]:
320 vetorx
= point
- last_point
# Vector spline section
321 # Tracking the selected objects
322 quat
= mathutils
.Vector
.to_track_quat(vetorx
, 'X', 'Z')
323 quat
= quat
.to_matrix().to_4x4()
325 v_len
= vetorx
.length
328 v_norm
= vetorx
/ v_len
329 while dx
>= dist
and leng
>= 0.0:
331 dx
-= dist
# Calculating the remaining length of the section
332 object = G_Objeto
[j
% len(G_Objeto
)]
335 context
.scene
.objects
.link(obj
)
336 obj
.matrix_world
= quat
* yawMatrix
* pitchMatrix
* rollMatrix
337 # Placing in the correct position
338 obj
.matrix_world
.translation
= point
- v_norm
* dx
339 obj
.scale
*= self
.scale
346 bpy
.utils
.register_class(PanelDupliCurve
)
347 bpy
.utils
.register_class(DupliCurve
)
351 bpy
.utils
.unregister_class(PanelDupliCurve
)
352 bpy
.utils
.unregister_class(DupliCurve
)
355 if __name__
== "__main__":