Fix error in rigify property generation
[blender-addons.git] / curve_tools / __init__.py
blobd7ce3736f65b648682070a99f71079fd048e246e
1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
18 # Contributed to by guy lateur, Alexander Meißner (Lichtso),
19 # Dealga McArdle (zeffii), Marvin.K.Breuer (MKB),
20 # Spivak Vladimir (cwolf3d)
21 # Originally an addon by Mackraken
24 bl_info = {
25 "name": "Curve Tools",
26 "description": "Adds some functionality for bezier/nurbs curve/surface modeling",
27 "author": "Mackraken",
28 "version": (0, 4, 5),
29 "blender": (2, 80, 0),
30 "location": "View3D > Tool Shelf > Edit Tab",
31 "warning": "WIP",
32 "doc_url": "{BLENDER_MANUAL_URL}/addons/add_curve/curve_tools.html",
33 "category": "Add Curve",
37 import os, bpy, importlib, math
38 from bpy.types import (
39 Operator,
40 Panel,
41 PropertyGroup,
43 from bpy.props import (
44 BoolProperty,
45 IntProperty,
46 FloatProperty,
47 EnumProperty,
48 CollectionProperty,
49 StringProperty,
50 FloatVectorProperty,
52 from . import properties, operators, auto_loft, outline, remove_doubles
53 from . import path_finder, show_resolution, splines_sequence, fillet
54 from . import internal, cad, toolpath, exports
56 if 'bpy' in locals():
57 importlib.reload(properties)
58 importlib.reload(operators)
59 importlib.reload(auto_loft)
60 importlib.reload(outline)
61 importlib.reload(remove_doubles)
62 importlib.reload(path_finder)
63 importlib.reload(show_resolution)
64 importlib.reload(splines_sequence)
65 importlib.reload(fillet)
66 importlib.reload(internal)
67 importlib.reload(cad)
68 importlib.reload(toolpath)
69 importlib.reload(exports)
71 from bpy.types import (
72 AddonPreferences,
76 def UpdateDummy(object, context):
77 scene = context.scene
78 SINGLEDROP = scene.UTSingleDrop
79 MOREDROP = scene.UTMOREDROP
80 LOFTDROP = scene.UTLoftDrop
81 ADVANCEDDROP = scene.UTAdvancedDrop
82 EXTENDEDDROP = scene.UTExtendedDrop
83 UTILSDROP = scene.UTUtilsDrop
86 class curvetoolsSettings(PropertyGroup):
87 # selection
88 SelectedObjects: CollectionProperty(
89 type=properties.curvetoolsSelectedObject
91 NrSelectedObjects: IntProperty(
92 name="NrSelectedObjects",
93 default=0,
94 description="Number of selected objects",
95 update=UpdateDummy
97 # curve
98 CurveLength: FloatProperty(
99 name="CurveLength",
100 default=0.0,
101 precision=6
103 # splines
104 SplineResolution: IntProperty(
105 name="SplineResolution",
106 default=64,
107 min=2, max=1024,
108 soft_min=2,
109 description="Spline resolution will be set to this value"
111 SplineRemoveLength: FloatProperty(
112 name="SplineRemoveLength",
113 default=0.001,
114 precision=6,
115 description="Splines shorter than this threshold length will be removed"
117 SplineJoinDistance: FloatProperty(
118 name="SplineJoinDistance",
119 default=0.001,
120 precision=6,
121 description="Splines with starting/ending points closer to each other "
122 "than this threshold distance will be joined"
124 SplineJoinStartEnd: BoolProperty(
125 name="SplineJoinStartEnd",
126 default=False,
127 description="Only join splines at the starting point of one and the ending point of the other"
129 splineJoinModeItems = (
130 ('At_midpoint', 'At midpoint', 'Join splines at midpoint of neighbouring points'),
131 ('Insert_segment', 'Insert segment', 'Insert segment between neighbouring points')
133 SplineJoinMode: EnumProperty(
134 items=splineJoinModeItems,
135 name="SplineJoinMode",
136 default='At_midpoint',
137 description="Determines how the splines will be joined"
139 # curve intersection
140 LimitDistance: FloatProperty(
141 name="LimitDistance",
142 default=0.0001,
143 precision=6,
144 description="Displays the result of the curve length calculation"
147 intAlgorithmItems = (
148 ('3D', '3D', 'Detect where curves intersect in 3D'),
149 ('From_View', 'From View', 'Detect where curves intersect in the RegionView3D')
151 IntersectCurvesAlgorithm: EnumProperty(
152 items=intAlgorithmItems,
153 name="IntersectCurvesAlgorithm",
154 description="Determines how the intersection points will be detected",
155 default='3D'
157 intModeItems = (
158 ('Insert', 'Insert', 'Insert points into the existing spline(s)'),
159 ('Split', 'Split', 'Split the existing spline(s) into 2'),
160 ('Empty', 'Empty', 'Add empty at intersections')
162 IntersectCurvesMode: EnumProperty(
163 items=intModeItems,
164 name="IntersectCurvesMode",
165 description="Determines what happens at the intersection points",
166 default='Split'
168 intAffectItems = (
169 ('Both', 'Both', 'Insert points into both curves'),
170 ('Active', 'Active', 'Insert points into active curve only'),
171 ('Other', 'Other', 'Insert points into other curve only')
173 IntersectCurvesAffect: EnumProperty(
174 items=intAffectItems,
175 name="IntersectCurvesAffect",
176 description="Determines which of the selected curves will be affected by the operation",
177 default='Both'
179 PathFinderRadius: FloatProperty(
180 name="PathFinder detection radius",
181 default=0.2,
182 precision=6,
183 description="PathFinder detection radius"
185 curve_vertcolor: FloatVectorProperty(
186 name="OUT",
187 default=(0.2, 0.9, 0.9, 1),
188 size=4,
189 subtype="COLOR",
190 min=0,
191 max=1
193 path_color: FloatVectorProperty(
194 name="OUT",
195 default=(0.2, 0.9, 0.9, 0.1),
196 size=4,
197 subtype="COLOR",
198 min=0,
199 max=1
201 path_thickness: IntProperty(
202 name="Path thickness",
203 default=10,
204 min=1, max=1024,
205 soft_min=2,
206 description="Path thickness (px)"
208 sequence_color: FloatVectorProperty(
209 name="OUT",
210 default=(0.2, 0.9, 0.9, 1),
211 size=4,
212 subtype="COLOR",
213 min=0,
214 max=1
216 font_thickness: IntProperty(
217 name="Font thickness",
218 default=2,
219 min=1, max=1024,
220 soft_min=2,
221 description="Font thickness (px)"
223 font_size: FloatProperty(
224 name="Font size",
225 default=0.1,
226 precision=3,
227 description="Font size"
231 # Curve Info
232 class VIEW3D_PT_curve_tools_info(Panel):
233 bl_space_type = "VIEW_3D"
234 bl_region_type = "UI"
235 bl_category = "Curve Edit"
236 bl_label = "Curve Info"
237 bl_options = {'DEFAULT_CLOSED'}
239 def draw(self, context):
240 scene = context.scene
241 layout = self.layout
243 col = layout.column(align=True)
244 col.operator("curvetools.operatorcurveinfo", text="Curve")
245 row = col.row(align=True)
246 row.operator("curvetools.operatorsplinesinfo", text="Spline")
247 row.operator("curvetools.operatorsegmentsinfo", text="Segment")
248 row = col.row(align=True)
249 row.operator("curvetools.operatorcurvelength", icon = "DRIVER_DISTANCE", text="Length")
250 row.prop(context.scene.curvetools, "CurveLength", text="")
252 # Curve Edit
253 class VIEW3D_PT_curve_tools_edit(Panel):
254 bl_space_type = "VIEW_3D"
255 bl_region_type = "UI"
256 bl_category = "Curve Edit"
257 bl_label = "Curve Edit"
260 def draw(self, context):
261 scene = context.scene
262 layout = self.layout
264 col = layout.column(align=True)
265 col.operator("curvetools.bezier_points_fillet", text='Fillet/Chamfer')
266 row = col.row(align=True)
267 row.operator("curvetools.outline", text="Outline")
268 row.operator("curvetools.add_toolpath_offset_curve", text="Recursive Offset")
269 col.operator("curvetools.sep_outline", text="Separate Offset/Selected")
270 col.operator("curvetools.bezier_cad_handle_projection", text='Extend Handles')
271 col.operator("curvetools.bezier_cad_boolean", text="Boolean Splines")
272 row = col.row(align=True)
273 row.operator("curvetools.bezier_spline_divide", text='Subdivide')
274 row.operator("curvetools.bezier_cad_subdivide", text="Multi Subdivide")
276 col.operator("curvetools.split", text='Split at Vertex')
277 col.operator("curvetools.add_toolpath_discretize_curve", text="Discretize Curve")
278 col.operator("curvetools.bezier_cad_array", text="Array Splines")
280 # Curve Intersect
281 class VIEW3D_PT_curve_tools_intersect(Panel):
282 bl_space_type = "VIEW_3D"
283 bl_region_type = "UI"
284 bl_category = "Curve Edit"
285 bl_label = "Intersect"
286 bl_options = {'DEFAULT_CLOSED'}
288 def draw(self, context):
289 scene = context.scene
290 layout = self.layout
292 col = layout.column(align=True)
293 col.operator("curvetools.bezier_curve_boolean", text="2D Curve Boolean")
294 col.operator("curvetools.operatorintersectcurves", text="Intersect Curves")
295 col.prop(context.scene.curvetools, "LimitDistance", text="Limit Distance")
296 col.prop(context.scene.curvetools, "IntersectCurvesAlgorithm", text="Algorithm")
297 col.prop(context.scene.curvetools, "IntersectCurvesMode", text="Mode")
298 col.prop(context.scene.curvetools, "IntersectCurvesAffect", text="Affect")
300 # Curve Surfaces
301 class VIEW3D_PT_curve_tools_surfaces(Panel):
302 bl_space_type = "VIEW_3D"
303 bl_region_type = "UI"
304 bl_category = "Curve Edit"
305 bl_label = "Surfaces"
306 bl_options = {'DEFAULT_CLOSED'}
308 def draw(self, context):
309 wm = context.window_manager
310 scene = context.scene
311 layout = self.layout
313 col = layout.column(align=True)
314 col.operator("curvetools.operatorbirail", text="Birail")
315 col.operator("curvetools.convert_bezier_to_surface", text="Convert Bezier to Surface")
316 col.operator("curvetools.convert_selected_face_to_bezier", text="Convert Faces to Bezier")
318 # Curve Path Finder
319 class VIEW3D_PT_curve_tools_loft(Panel):
320 bl_space_type = "VIEW_3D"
321 bl_region_type = "UI"
322 bl_category = "Curve Edit"
323 bl_parent_id = "VIEW3D_PT_curve_tools_surfaces"
324 bl_label = "Loft"
325 bl_options = {'DEFAULT_CLOSED'}
327 def draw(self, context):
328 wm = context.window_manager
329 scene = context.scene
330 layout = self.layout
332 col = layout.column(align=True)
333 col.operator("curvetools.create_auto_loft")
334 lofters = [o for o in scene.objects if "autoloft" in o.keys()]
335 for o in lofters:
336 col.label(text=o.name)
337 # layout.prop(o, '["autoloft"]', toggle=True)
338 col.prop(wm, "auto_loft", toggle=True)
339 col.operator("curvetools.update_auto_loft_curves")
340 col = layout.column(align=True)
343 # Curve Sanitize
344 class VIEW3D_PT_curve_tools_sanitize(Panel):
345 bl_space_type = "VIEW_3D"
346 bl_region_type = "UI"
347 bl_category = "Curve Edit"
348 bl_label = "Sanitize"
349 bl_options = {'DEFAULT_CLOSED'}
351 def draw(self, context):
352 scene = context.scene
353 layout = self.layout
355 col = layout.column(align=True)
356 col.operator("curvetools.operatororigintospline0start", icon = "OBJECT_ORIGIN", text="Set Origin to Spline Start")
357 col.operator("curvetools.scale_reset", text='Reset Scale')
359 col.label(text="Cleanup:")
360 col.operator("curvetools.remove_doubles", icon = "TRASH", text='Remove Doubles')
361 col.operator("curvetools.operatorsplinesremovezerosegment", icon = "TRASH", text="0-Segment Splines")
362 row = col.row(align=True)
363 row.operator("curvetools.operatorsplinesremoveshort", text="Short Splines")
364 row.prop(context.scene.curvetools, "SplineRemoveLength", text="Threshold remove")
366 col.label(text="Join Splines:")
367 col.operator("curvetools.operatorsplinesjoinneighbouring", text="Join Neighbouring Splines")
368 row = col.row(align=True)
369 col.prop(context.scene.curvetools, "SplineJoinDistance", text="Threshold")
370 col.prop(context.scene.curvetools, "SplineJoinStartEnd", text="Only at Ends")
371 col.prop(context.scene.curvetools, "SplineJoinMode", text="Join Position")
373 # Curve Utilities
374 class VIEW3D_PT_curve_tools_utilities(Panel):
375 bl_space_type = "VIEW_3D"
376 bl_region_type = "UI"
377 bl_category = "Curve Edit"
378 bl_label = "Utilities"
379 bl_options = {'DEFAULT_CLOSED'}
381 def draw(self, context):
382 scene = context.scene
383 layout = self.layout
385 col = layout.column(align=True)
386 row = col.row(align=True)
387 row.label(text="Curve Resolution:")
388 row = col.row(align=True)
389 row.operator("curvetools.show_resolution", icon="HIDE_OFF", text="Show [ESC]")
390 row.prop(context.scene.curvetools, "curve_vertcolor", text="")
391 row = col.row(align=True)
392 row.operator("curvetools.operatorsplinessetresolution", text="Set Resolution")
393 row.prop(context.scene.curvetools, "SplineResolution", text="")
396 row = col.row(align=True)
397 row.label(text="Spline Order:")
398 row = col.row(align=True)
399 row.operator("curvetools.show_splines_sequence", icon="HIDE_OFF", text="Show [ESC]")
400 row.prop(context.scene.curvetools, "sequence_color", text="")
401 row = col.row(align=True)
402 row.prop(context.scene.curvetools, "font_size", text="Font Size")
403 row.prop(context.scene.curvetools, "font_thickness", text="Font Thickness")
404 row = col.row(align=True)
405 oper = row.operator("curvetools.rearrange_spline", text = "<")
406 oper.command = 'PREV'
407 oper = row.operator("curvetools.rearrange_spline", text = ">")
408 oper.command = 'NEXT'
409 row = col.row(align=True)
410 row.operator("curve.switch_direction", text="Switch Direction")
411 row = col.row(align=True)
412 row.operator("curvetools.set_first_points", text="Set First Points")
414 # Curve Path Finder
415 class VIEW3D_PT_curve_tools_pathfinder(Panel):
416 bl_space_type = "VIEW_3D"
417 bl_region_type = "UI"
418 bl_category = "Curve Edit"
419 bl_parent_id = "VIEW3D_PT_curve_tools_utilities"
420 bl_label = "Path Finder"
421 bl_options = {'DEFAULT_CLOSED'}
423 def draw(self, context):
424 scene = context.scene
425 layout = self.layout
427 col = layout.column(align=True)
428 col.operator("curvetools.pathfinder", text="Path Finder [ESC]")
429 col.prop(context.scene.curvetools, "PathFinderRadius", text="PathFinder Radius")
430 col.prop(context.scene.curvetools, "path_color", text="")
431 col.prop(context.scene.curvetools, "path_thickness", text="Thickness")
433 col = layout.column(align=True)
434 col.label(text="ESC or TAB - Exit PathFinder")
435 col.label(text="X or DEL - Delete")
436 col.label(text="Alt + Mouse Click - Select Spline")
437 col.label(text="Alt + Shift + Mouse click - Add Spline to Selection")
438 col.label(text="A - Deselect All")
440 # Add-ons Preferences Update Panel
442 # Define Panel classes for updating
443 panels = (
444 VIEW3D_PT_curve_tools_info, VIEW3D_PT_curve_tools_edit,
445 VIEW3D_PT_curve_tools_intersect, VIEW3D_PT_curve_tools_surfaces,
446 VIEW3D_PT_curve_tools_loft, VIEW3D_PT_curve_tools_sanitize,
447 VIEW3D_PT_curve_tools_utilities, VIEW3D_PT_curve_tools_pathfinder
451 def update_panel(self, context):
452 message = "Curve Tools: Updating Panel locations has failed"
453 try:
454 for panel in panels:
455 if "bl_rna" in panel.__dict__:
456 bpy.utils.unregister_class(panel)
458 for panel in panels:
459 panel.bl_category = context.preferences.addons[__name__].preferences.category
460 bpy.utils.register_class(panel)
462 except Exception as e:
463 print("\n[{}]\n{}\n\nError:\n{}".format(__name__, message, e))
464 pass
467 class CurveAddonPreferences(AddonPreferences):
468 # this must match the addon name, use '__package__'
469 # when defining this in a submodule of a python package.
470 bl_idname = __name__
472 category: StringProperty(
473 name="Tab Category",
474 description="Choose a name for the category of the panel",
475 default="Edit",
476 update=update_panel
479 def draw(self, context):
480 layout = self.layout
482 row = layout.row()
483 col = row.column()
484 col.label(text="Tab Category:")
485 col.prop(self, "category", text="")
487 # Context MENU
488 def curve_tools_context_menu(self, context):
489 bl_label = 'Curve tools'
491 self.layout.operator("curvetools.bezier_points_fillet", text="Fillet")
492 self.layout.operator("curvetools.bezier_cad_handle_projection", text='Handle Projection')
493 self.layout.operator("curvetools.bezier_spline_divide", text="Divide")
494 self.layout.operator("curvetools.add_toolpath_offset_curve", text="Offset Curve")
495 self.layout.operator("curvetools.remove_doubles", text='Remove Doubles')
496 self.layout.separator()
498 def curve_tools_object_context_menu(self, context):
499 bl_label = 'Curve tools'
501 if context.active_object.type == "CURVE":
502 self.layout.operator("curvetools.scale_reset", text="Scale Reset")
503 self.layout.operator("curvetools.add_toolpath_offset_curve", text="Offset Curve")
504 self.layout.operator("curvetools.remove_doubles", text='Remove Doubles')
505 self.layout.separator()
507 # Import-export 2d svg
508 def menu_file_export(self, context):
509 for operator in exports.operators:
510 self.layout.operator(operator.bl_idname)
512 def menu_file_import(self, context):
513 for operator in imports.operators:
514 self.layout.operator(operator.bl_idname)
516 # REGISTER
517 classes = cad.operators + \
518 toolpath.operators + \
519 exports.operators + \
520 operators.operators + \
521 properties.operators + \
522 path_finder.operators + \
523 show_resolution.operators + \
524 splines_sequence.operators + \
525 outline.operators + \
526 fillet.operators + \
527 remove_doubles.operators + \
529 CurveAddonPreferences,
530 curvetoolsSettings,
533 def register():
534 bpy.types.Scene.UTSingleDrop = BoolProperty(
535 name="One Curve",
536 default=False,
537 description="One Curve"
539 bpy.types.Scene.UTMOREDROP = BoolProperty(
540 name="Curves",
541 default=False,
542 description="Curves"
544 bpy.types.Scene.UTLoftDrop = BoolProperty(
545 name="Two Curves Loft",
546 default=False,
547 description="Two Curves Loft"
549 bpy.types.Scene.UTAdvancedDrop = BoolProperty(
550 name="Advanced",
551 default=True,
552 description="Advanced"
554 bpy.types.Scene.UTExtendedDrop = BoolProperty(
555 name="Extended",
556 default=False,
557 description="Extended"
559 bpy.types.Scene.UTUtilsDrop = BoolProperty(
560 name="Curves Utils",
561 default=True,
562 description="Curves Utils"
565 for cls in classes:
566 bpy.utils.register_class(cls)
568 for panel in panels:
569 bpy.utils.register_class(panel)
571 auto_loft.register()
573 bpy.types.TOPBAR_MT_file_export.append(menu_file_export)
575 bpy.types.Scene.curvetools = bpy.props.PointerProperty(type=curvetoolsSettings)
577 update_panel(None, bpy.context)
579 bpy.types.VIEW3D_MT_edit_curve_context_menu.prepend(curve_tools_context_menu)
580 bpy.types.VIEW3D_MT_object_context_menu.prepend(curve_tools_object_context_menu)
583 def unregister():
584 del bpy.types.Scene.UTSingleDrop
585 del bpy.types.Scene.UTMOREDROP
586 del bpy.types.Scene.UTLoftDrop
587 del bpy.types.Scene.UTAdvancedDrop
588 del bpy.types.Scene.UTExtendedDrop
589 del bpy.types.Scene.UTUtilsDrop
591 auto_loft.unregister()
593 bpy.types.TOPBAR_MT_file_export.remove(menu_file_export)
595 bpy.types.VIEW3D_MT_edit_curve_context_menu.remove(curve_tools_context_menu)
596 bpy.types.VIEW3D_MT_object_context_menu.remove(curve_tools_object_context_menu)
598 for panel in panels:
599 bpy.utils.unregister_class(panel)
601 for cls in classes:
602 bpy.utils.unregister_class(cls)
605 if __name__ == "__main__":
606 register()