1 # SPDX-FileCopyrightText: 2019-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
9 from bpy
.props
import *
10 from bpy_extras
import object_utils
, view3d_utils
11 from mathutils
import *
14 from . import properties
16 from . import intersections
18 from . import surfaces
19 from . import mathematics
20 from . import internal
24 class OperatorCurveInfo(bpy
.types
.Operator
):
25 bl_idname
= "curvetools.operatorcurveinfo"
27 bl_description
= "Displays general info about the active/selected curve"
31 def poll(cls
, context
):
32 return util
.Selected1Curve()
35 def execute(self
, context
):
36 curve
= curves
.Curve(context
.active_object
)
38 nrSplines
= len(curve
.splines
)
41 for spline
in curve
.splines
:
42 nrSegments
+= spline
.nrSegments
43 if spline
.nrSegments
< 1: nrEmptySplines
+= 1
46 self
.report({'INFO'}, "nrSplines: %d; nrSegments: %d; nrEmptySplines: %d" % (nrSplines
, nrSegments
, nrEmptySplines
))
52 class OperatorCurveLength(bpy
.types
.Operator
):
53 bl_idname
= "curvetools.operatorcurvelength"
55 bl_description
= "Calculates the length of the active/selected curves"
59 def poll(cls
, context
):
60 return util
.Selected1OrMoreCurves()
63 def execute(self
, context
):
64 selCurves
= util
.GetSelectedCurves()
67 for blCurve
in selCurves
:
68 curve
= curves
.Curve(blCurve
)
69 length
+= curve
.length
71 context
.scene
.curvetools
.CurveLength
= length
77 class OperatorSplinesInfo(bpy
.types
.Operator
):
78 bl_idname
= "curvetools.operatorsplinesinfo"
80 bl_description
= "Displays general info about the splines of the active/selected curve"
84 def poll(cls
, context
):
85 return util
.Selected1Curve()
88 def execute(self
, context
):
89 curve
= curves
.Curve(context
.active_object
)
90 nrSplines
= len(curve
.splines
)
93 print("OperatorSplinesInfo:", "nrSplines:", nrSplines
)
96 for iSpline
, spline
in enumerate(curve
.splines
):
97 print("--", "spline %d of %d: nrSegments: %d" % (iSpline
+ 1, nrSplines
, spline
.nrSegments
))
99 if spline
.nrSegments
< 1:
101 print("--", "--", "## WARNING: spline has no segments and will therefor be ignored in any further calculations")
104 self
.report({'INFO'}, "nrSplines: %d; nrEmptySplines: %d" % (nrSplines
, nrEmptySplines
) + " -- more info: see console")
110 class OperatorSegmentsInfo(bpy
.types
.Operator
):
111 bl_idname
= "curvetools.operatorsegmentsinfo"
113 bl_description
= "Displays general info about the segments of the active/selected curve"
117 def poll(cls
, context
):
118 return util
.Selected1Curve()
121 def execute(self
, context
):
122 curve
= curves
.Curve(context
.active_object
)
123 nrSplines
= len(curve
.splines
)
127 print("OperatorSegmentsInfo:", "nrSplines:", nrSplines
)
130 for iSpline
, spline
in enumerate(curve
.splines
):
131 nrSegmentsSpline
= spline
.nrSegments
132 print("--", "spline %d of %d: nrSegments: %d" % (iSpline
+ 1, nrSplines
, nrSegmentsSpline
))
134 if nrSegmentsSpline
< 1:
136 print("--", "--", "## WARNING: spline has no segments and will therefor be ignored in any further calculations")
139 for iSegment
, segment
in enumerate(spline
.segments
):
140 print("--", "--", "segment %d of %d coefficients:" % (iSegment
+ 1, nrSegmentsSpline
))
141 print("--", "--", "--", "C0: %.6f, %.6f, %.6f" % (segment
.coeff0
.x
, segment
.coeff0
.y
, segment
.coeff0
.z
))
143 nrSegments
+= nrSegmentsSpline
145 self
.report({'INFO'}, "nrSplines: %d; nrSegments: %d; nrEmptySplines: %d" % (nrSplines
, nrSegments
, nrEmptySplines
))
151 class OperatorOriginToSpline0Start(bpy
.types
.Operator
):
152 bl_idname
= "curvetools.operatororigintospline0start"
153 bl_label
= "OriginToSpline0Start"
154 bl_description
= "Sets the origin of the active/selected curve to the starting point of the (first) spline. Nice for curve modifiers"
155 bl_options
= {'UNDO'}
159 def poll(cls
, context
):
160 return util
.Selected1Curve()
163 def execute(self
, context
):
166 blCurve
= context
.active_object
167 blSpline
= blCurve
.data
.splines
[0]
168 newOrigin
= blCurve
.matrix_world
@ blSpline
.bezier_points
[0].co
170 origOrigin
= bpy
.context
.scene
.cursor
.location
.copy()
171 self
.report({'INFO'}, "origOrigin: %.6f, %.6f, %.6f" % (origOrigin
.x
, origOrigin
.y
, origOrigin
.z
))
172 self
.report({'INFO'}, "newOrigin: %.6f, %.6f, %.6f" % (newOrigin
.x
, newOrigin
.y
, newOrigin
.z
))
174 current_mode
= bpy
.context
.object.mode
176 bpy
.ops
.object.mode_set(mode
= 'OBJECT')
177 bpy
.context
.scene
.cursor
.location
= newOrigin
178 bpy
.ops
.object.origin_set(type='ORIGIN_CURSOR')
179 bpy
.context
.scene
.cursor
.location
= origOrigin
181 bpy
.ops
.object.mode_set (mode
= current_mode
)
189 class OperatorIntersectCurves(bpy
.types
.Operator
):
190 bl_idname
= "curvetools.operatorintersectcurves"
191 bl_label
= "Intersect"
192 bl_description
= "Intersects selected curves"
193 bl_options
= {'UNDO'}
197 def poll(cls
, context
):
198 return util
.Selected2OrMoreCurves()
201 def execute(self
, context
):
202 print("### TODO: OperatorIntersectcurves.execute()")
204 algo
= context
.scene
.curvetools
.IntersectCurvesAlgorithm
205 print("-- algo:", algo
)
208 mode
= context
.scene
.curvetools
.IntersectCurvesMode
209 print("-- mode:", mode
)
210 # if mode == 'Split':
211 # self.report({'WARNING'}, "'Split' mode is not implemented yet -- <<STOPPING>>")
212 # return {'CANCELLED'}
214 affect
= context
.scene
.curvetools
.IntersectCurvesAffect
215 print("-- affect:", affect
)
217 selected_objects
= context
.selected_objects
218 lenodjs
= len(selected_objects
)
219 print('lenodjs:', lenodjs
)
220 for i
in range(0, lenodjs
):
221 for j
in range(0, lenodjs
):
223 bpy
.ops
.object.select_all(action
='DESELECT')
224 selected_objects
[i
].select_set(True)
225 selected_objects
[j
].select_set(True)
227 if selected_objects
[i
].type == 'CURVE' and selected_objects
[j
].type == 'CURVE':
228 curveIntersector
= intersections
.CurvesIntersector
.FromSelection()
229 rvIntersectionNrs
= curveIntersector
.CalcAndApplyIntersections()
231 self
.report({'INFO'}, "Active curve points: %d; other curve points: %d" % (rvIntersectionNrs
[0], rvIntersectionNrs
[1]))
233 for obj
in selected_objects
:
238 # ------------------------------------------------------------
241 class OperatorLoftCurves(bpy
.types
.Operator
):
242 bl_idname
= "curvetools.operatorloftcurves"
244 bl_description
= "Lofts selected curves"
245 bl_options
= {'UNDO'}
249 def poll(cls
, context
):
250 return util
.Selected2Curves()
253 def execute(self
, context
):
254 #print("### TODO: OperatorLoftcurves.execute()")
256 loftedSurface
= surfaces
.LoftedSurface
.FromSelection()
257 loftedSurface
.AddToScene()
259 self
.report({'INFO'}, "OperatorLoftcurves.execute()")
264 # ------------------------------------------------------------
265 # OperatorSweepCurves
267 class OperatorSweepCurves(bpy
.types
.Operator
):
268 bl_idname
= "curvetools.operatorsweepcurves"
270 bl_description
= "Sweeps the active curve along to other curve (rail)"
271 bl_options
= {'UNDO'}
275 def poll(cls
, context
):
276 return util
.Selected2Curves()
279 def execute(self
, context
):
280 #print("### TODO: OperatorSweepcurves.execute()")
282 sweptSurface
= surfaces
.SweptSurface
.FromSelection()
283 sweptSurface
.AddToScene()
285 self
.report({'INFO'}, "OperatorSweepcurves.execute()")
293 class OperatorBirail(bpy
.types
.Operator
):
294 bl_idname
= "curvetools.operatorbirail"
296 bl_description
= "Generates a birailed surface from 3 selected curves -- in order: rail1, rail2 and profile"
297 bl_options
= {'UNDO'}
301 def poll(cls
, context
):
302 return util
.Selected3Curves()
305 def execute(self
, context
):
306 birailedSurface
= surfaces
.BirailedSurface
.FromSelection()
307 birailedSurface
.AddToScene()
309 self
.report({'INFO'}, "OperatorBirail.execute()")
315 # 1 OR MORE CURVES SELECTED
316 # #########################
317 class OperatorSplinesSetResolution(bpy
.types
.Operator
):
318 bl_idname
= "curvetools.operatorsplinessetresolution"
319 bl_label
= "SplinesSetResolution"
320 bl_description
= "Sets the resolution of all splines"
321 bl_options
= {'UNDO'}
325 def poll(cls
, context
):
326 return util
.Selected1OrMoreCurves()
329 def execute(self
, context
):
330 splRes
= context
.scene
.curvetools
.SplineResolution
331 selCurves
= util
.GetSelectedCurves()
333 for blCurve
in selCurves
:
334 for spline
in blCurve
.data
.splines
:
335 spline
.resolution_u
= splRes
339 # ------------------------------------------------------------
340 # OperatorSplinesRemoveZeroSegment
342 class OperatorSplinesRemoveZeroSegment(bpy
.types
.Operator
):
343 bl_idname
= "curvetools.operatorsplinesremovezerosegment"
344 bl_label
= "SplinesRemoveZeroSegment"
345 bl_description
= "Removes splines with no segments -- they seem to creep up, sometimes"
346 bl_options
= {'UNDO'}
350 def poll(cls
, context
):
351 return util
.Selected1OrMoreCurves()
354 def execute(self
, context
):
355 selCurves
= util
.GetSelectedCurves()
357 for blCurve
in selCurves
:
358 curve
= curves
.Curve(blCurve
)
359 nrSplines
= curve
.nrSplines
362 for spline
in curve
.splines
:
363 if len(spline
.segments
) < 1: splinesToRemove
.append(spline
)
364 nrRemovedSplines
= len(splinesToRemove
)
366 for spline
in splinesToRemove
: curve
.splines
.remove(spline
)
368 if nrRemovedSplines
> 0: curve
.RebuildInScene()
370 self
.report({'INFO'}, "Removed %d of %d splines" % (nrRemovedSplines
, nrSplines
))
374 # ------------------------------------------------------------
375 # OperatorSplinesRemoveShort
377 class OperatorSplinesRemoveShort(bpy
.types
.Operator
):
378 bl_idname
= "curvetools.operatorsplinesremoveshort"
379 bl_label
= "SplinesRemoveShort"
380 bl_description
= "Removes splines with a length smaller than the threshold"
381 bl_options
= {'UNDO'}
385 def poll(cls
, context
):
386 return util
.Selected1OrMoreCurves()
389 def execute(self
, context
):
390 threshold
= context
.scene
.curvetools
.SplineRemoveLength
391 selCurves
= util
.GetSelectedCurves()
393 for blCurve
in selCurves
:
394 curve
= curves
.Curve(blCurve
)
395 nrSplines
= curve
.nrSplines
397 nrRemovedSplines
= curve
.RemoveShortSplines(threshold
)
398 if nrRemovedSplines
> 0: curve
.RebuildInScene()
400 self
.report({'INFO'}, "Removed %d of %d splines" % (nrRemovedSplines
, nrSplines
))
404 # ------------------------------------------------------------
405 # OperatorSplinesJoinNeighbouring
407 class OperatorSplinesJoinNeighbouring(bpy
.types
.Operator
):
408 bl_idname
= "curvetools.operatorsplinesjoinneighbouring"
409 bl_label
= "SplinesJoinNeighbouring"
410 bl_description
= "Joins neighbouring splines within a distance smaller than the threshold"
411 bl_options
= {'UNDO'}
415 def poll(cls
, context
):
416 return util
.Selected1OrMoreCurves()
419 def execute(self
, context
):
420 selCurves
= util
.GetSelectedCurves()
422 for blCurve
in selCurves
:
423 curve
= curves
.Curve(blCurve
)
424 nrSplines
= curve
.nrSplines
426 threshold
= context
.scene
.curvetools
.SplineJoinDistance
427 startEnd
= context
.scene
.curvetools
.SplineJoinStartEnd
428 mode
= context
.scene
.curvetools
.SplineJoinMode
430 nrJoins
= curve
.JoinNeighbouringSplines(startEnd
, threshold
, mode
)
431 if nrJoins
> 0: curve
.RebuildInScene()
433 self
.report({'INFO'}, "Applied %d joins on %d splines; resulting nrSplines: %d" % (nrJoins
, nrSplines
, curve
.nrSplines
))
437 # ------------------------------------------------------------
440 def SurfaceFromBezier(surfacedata
, points
, center
):
442 len_points
= len(points
) - 1
444 if len_points
% 2 == 0:
445 h
= mathematics
.subdivide_cubic_bezier(
446 points
[len_points
].co
, points
[len_points
].handle_right
,
447 points
[0].handle_left
, points
[0].co
, 0.5
450 len_points
= len(points
) - 1
451 points
[len_points
- 1].handle_right
= h
[0]
452 points
[len_points
].handle_left
= h
[1]
453 points
[len_points
].co
= h
[2]
454 points
[len_points
].handle_right
= h
[3]
455 points
[0].handle_left
= h
[4]
457 half
= round((len_points
+ 1)/2) - 1
459 surfacespline1
= surfacedata
.splines
.new(type='NURBS')
460 surfacespline1
.points
.add(3)
461 surfacespline1
.points
[0].co
= [points
[0].co
.x
, points
[0].co
.y
, points
[0].co
.z
, 1]
462 surfacespline1
.points
[1].co
= [points
[0].handle_left
.x
, points
[0].handle_left
.y
, points
[0].handle_left
.z
, 1]
463 surfacespline1
.points
[2].co
= [points
[len_points
].handle_right
.x
,points
[len_points
].handle_right
.y
, points
[len_points
].handle_right
.z
, 1]
464 surfacespline1
.points
[3].co
= [points
[len_points
].co
.x
, points
[len_points
].co
.y
, points
[len_points
].co
.z
, 1]
465 for p
in surfacespline1
.points
:
467 surfacespline1
.use_endpoint_u
= True
468 surfacespline1
.use_endpoint_v
= True
470 for i
in range(0, half
):
474 surfacespline2
= surfacedata
.splines
.new(type='NURBS')
475 surfacespline2
.points
.add(3)
476 surfacespline2
.points
[0].co
= [points
[i
].co
.x
, points
[i
].co
.y
, points
[i
].co
.z
, 1]
477 surfacespline2
.points
[1].co
= [(points
[i
].co
.x
+ points
[len_points
- i
].co
.x
)/2,
478 (points
[i
].co
.y
+ points
[len_points
- i
].co
.y
)/2,
479 (points
[i
].co
.z
+ points
[len_points
- i
].co
.z
)/2, 1]
480 surfacespline2
.points
[2].co
= [(points
[len_points
- i
].co
.x
+ points
[i
].co
.x
)/2,
481 (points
[len_points
- i
].co
.y
+ points
[i
].co
.y
)/2,
482 (points
[len_points
- i
].co
.z
+ points
[i
].co
.z
)/2, 1]
483 surfacespline2
.points
[3].co
= [points
[len_points
- i
].co
.x
, points
[len_points
- i
].co
.y
, points
[len_points
- i
].co
.z
, 1]
484 for p
in surfacespline2
.points
:
486 surfacespline2
.use_endpoint_u
= True
487 surfacespline2
.use_endpoint_v
= True
490 surfacespline3
= surfacedata
.splines
.new(type='NURBS')
491 surfacespline3
.points
.add(3)
492 surfacespline3
.points
[0].co
= [points
[i
].handle_right
.x
, points
[i
].handle_right
.y
, points
[i
].handle_right
.z
, 1]
493 surfacespline3
.points
[1].co
= [(points
[i
].handle_right
.x
+ points
[len_points
- i
].handle_left
.x
)/2,
494 (points
[i
].handle_right
.y
+ points
[len_points
- i
].handle_left
.y
)/2,
495 (points
[i
].handle_right
.z
+ points
[len_points
- i
].handle_left
.z
)/2, 1]
496 surfacespline3
.points
[2].co
= [(points
[len_points
- i
].handle_left
.x
+ points
[i
].handle_right
.x
)/2,
497 (points
[len_points
- i
].handle_left
.y
+ points
[i
].handle_right
.y
)/2,
498 (points
[len_points
- i
].handle_left
.z
+ points
[i
].handle_right
.z
)/2, 1]
499 surfacespline3
.points
[3].co
= [points
[len_points
- i
].handle_left
.x
, points
[len_points
- i
].handle_left
.y
, points
[len_points
- i
].handle_left
.z
, 1]
500 for p
in surfacespline3
.points
:
502 surfacespline3
.use_endpoint_u
= True
503 surfacespline3
.use_endpoint_v
= True
506 surfacespline4
= surfacedata
.splines
.new(type='NURBS')
507 surfacespline4
.points
.add(3)
508 surfacespline4
.points
[0].co
= [points
[i
+ 1].handle_left
.x
, points
[i
+ 1].handle_left
.y
, points
[i
+ 1].handle_left
.z
, 1]
509 surfacespline4
.points
[1].co
= [(points
[i
+ 1].handle_left
.x
+ points
[len_points
- i
- 1].handle_right
.x
)/2,
510 (points
[i
+ 1].handle_left
.y
+ points
[len_points
- i
- 1].handle_right
.y
)/2,
511 (points
[i
+ 1].handle_left
.z
+ points
[len_points
- i
- 1].handle_right
.z
)/2, 1]
512 surfacespline4
.points
[2].co
= [(points
[len_points
- i
- 1].handle_right
.x
+ points
[i
+ 1].handle_left
.x
)/2,
513 (points
[len_points
- i
- 1].handle_right
.y
+ points
[i
+ 1].handle_left
.y
)/2,
514 (points
[len_points
- i
- 1].handle_right
.z
+ points
[i
+ 1].handle_left
.z
)/2, 1]
515 surfacespline4
.points
[3].co
= [points
[len_points
- i
- 1].handle_right
.x
, points
[len_points
- i
- 1].handle_right
.y
, points
[len_points
- i
- 1].handle_right
.z
, 1]
516 for p
in surfacespline4
.points
:
518 surfacespline4
.use_endpoint_u
= True
519 surfacespline4
.use_endpoint_v
= True
523 surfacespline5
= surfacedata
.splines
.new(type='NURBS')
524 surfacespline5
.points
.add(3)
525 surfacespline5
.points
[0].co
= [points
[i
+ 1].co
.x
, points
[i
+ 1].co
.y
, points
[i
+ 1].co
.z
, 1]
526 surfacespline5
.points
[1].co
= [(points
[i
+ 1].co
.x
+ points
[len_points
- i
- 1].co
.x
)/2,
527 (points
[i
+ 1].co
.y
+ points
[len_points
- i
- 1].co
.y
)/2,
528 (points
[i
+ 1].co
.z
+ points
[len_points
- i
- 1].co
.z
)/2, 1]
529 surfacespline5
.points
[2].co
= [(points
[len_points
- i
- 1].co
.x
+ points
[i
+ 1].co
.x
)/2,
530 (points
[len_points
- i
- 1].co
.y
+ points
[i
+ 1].co
.y
)/2,
531 (points
[len_points
- i
- 1].co
.z
+ points
[i
+ 1].co
.z
)/2, 1]
532 surfacespline5
.points
[3].co
= [points
[len_points
- i
- 1].co
.x
, points
[len_points
- i
- 1].co
.y
, points
[len_points
- i
- 1].co
.z
, 1]
533 for p
in surfacespline5
.points
:
535 surfacespline5
.use_endpoint_u
= True
536 surfacespline5
.use_endpoint_v
= True
539 surfacespline6
= surfacedata
.splines
.new(type='NURBS')
540 surfacespline6
.points
.add(3)
541 surfacespline6
.points
[0].co
= [points
[half
].co
.x
, points
[half
].co
.y
, points
[half
].co
.z
, 1]
542 surfacespline6
.points
[1].co
= [points
[half
].handle_right
.x
, points
[half
].handle_right
.y
, points
[half
].handle_right
.z
, 1]
543 surfacespline6
.points
[2].co
= [points
[half
+1].handle_left
.x
, points
[half
+1].handle_left
.y
, points
[half
+1].handle_left
.z
, 1]
544 surfacespline6
.points
[3].co
= [points
[half
+1].co
.x
, points
[half
+1].co
.y
, points
[half
+1].co
.z
, 1]
545 for p
in surfacespline6
.points
:
547 surfacespline6
.use_endpoint_u
= True
548 surfacespline6
.use_endpoint_v
= True
550 bpy
.ops
.object.mode_set(mode
= 'EDIT')
551 bpy
.ops
.curve
.make_segment()
553 for s
in surfacedata
.splines
:
561 # ------------------------------------------------------------
562 # Convert selected faces to Bezier
564 class ConvertSelectedFacesToBezier(bpy
.types
.Operator
):
565 bl_idname
= "curvetools.convert_selected_face_to_bezier"
566 bl_label
= "Convert selected faces to Bezier"
567 bl_description
= "Convert selected faces to Bezier"
568 bl_options
= {'REGISTER', 'UNDO'}
571 def poll(cls
, context
):
572 return util
.Selected1Mesh()
574 def execute(self
, context
):
576 bpy
.ops
.object.mode_set(mode
= 'OBJECT')
577 active_object
= context
.active_object
578 meshdata
= active_object
.data
579 curvedata
= bpy
.data
.curves
.new('Curve' + active_object
.name
, type='CURVE')
580 curveobject
= object_utils
.object_data_add(context
, curvedata
)
581 curvedata
.dimensions
= '3D'
583 for poly
in meshdata
.polygons
:
585 newSpline
= curvedata
.splines
.new(type='BEZIER')
586 newSpline
.use_cyclic_u
= True
587 newSpline
.bezier_points
.add(poly
.loop_total
- 1)
589 for loop_index
in range(poly
.loop_start
, poly
.loop_start
+ poly
.loop_total
):
590 newSpline
.bezier_points
[npoint
].co
= meshdata
.vertices
[meshdata
.loops
[loop_index
].vertex_index
].co
591 newSpline
.bezier_points
[npoint
].handle_left_type
= 'VECTOR'
592 newSpline
.bezier_points
[npoint
].handle_right_type
= 'VECTOR'
593 newSpline
.bezier_points
[npoint
].select_control_point
= True
594 newSpline
.bezier_points
[npoint
].select_left_handle
= True
595 newSpline
.bezier_points
[npoint
].select_right_handle
= True
600 # ------------------------------------------------------------
601 # Convert Bezier to Surface
603 class ConvertBezierToSurface(bpy
.types
.Operator
):
604 bl_idname
= "curvetools.convert_bezier_to_surface"
605 bl_label
= "Convert Bezier to Surface"
606 bl_description
= "Convert Bezier to Surface"
607 bl_options
= {'REGISTER', 'UNDO'}
609 Center
: BoolProperty(
612 description
="Consider center points"
615 Resolution_U
: IntProperty(
620 description
="Surface resolution U"
623 Resolution_V
: IntProperty(
628 description
="Surface resolution V"
631 def draw(self
, context
):
635 col
= layout
.column()
636 col
.prop(self
, 'Center')
637 col
.prop(self
, 'Resolution_U')
638 col
.prop(self
, 'Resolution_V')
641 def poll(cls
, context
):
642 return util
.Selected1OrMoreCurves()
644 def execute(self
, context
):
646 bpy
.ops
.object.mode_set(mode
= 'OBJECT')
647 active_object
= context
.active_object
648 curvedata
= active_object
.data
650 surfacedata
= bpy
.data
.curves
.new('Surface', type='SURFACE')
651 surfaceobject
= object_utils
.object_data_add(context
, surfacedata
)
652 surfaceobject
.matrix_world
= active_object
.matrix_world
653 surfaceobject
.rotation_euler
= active_object
.rotation_euler
654 surfacedata
.dimensions
= '3D'
655 surfaceobject
.show_wire
= True
656 surfaceobject
.show_in_front
= True
658 for spline
in curvedata
.splines
:
659 SurfaceFromBezier(surfacedata
, spline
.bezier_points
, self
.Center
)
661 for spline
in surfacedata
.splines
:
662 len_p
= len(spline
.points
)
663 len_devide_4
= round(len_p
/ 4) + 1
664 len_devide_2
= round(len_p
/ 2)
665 bpy
.ops
.object.mode_set(mode
= 'EDIT')
666 for point_index
in range(len_devide_4
, len_p
- len_devide_4
):
667 if point_index
!= len_devide_2
and point_index
!= len_devide_2
- 1:
668 spline
.points
[point_index
].select
= True
670 surfacedata
.resolution_u
= self
.Resolution_U
671 surfacedata
.resolution_v
= self
.Resolution_V
675 # ------------------------------------------------------------
678 class BezierPointsFillet(bpy
.types
.Operator
):
679 bl_idname
= "curvetools.bezier_points_fillet"
680 bl_label
= "Bezier points Fillet"
681 bl_description
= "Bezier points Fillet"
682 bl_options
= {'REGISTER', 'UNDO', 'PRESET'}
684 Fillet_radius
: FloatProperty(
690 Types
= [('Round', "Round", "Round"),
691 ('Chamfer', "Chamfer", "Chamfer")]
692 Fillet_Type
: EnumProperty(
694 description
="Fillet type",
698 def draw(self
, context
):
702 col
= layout
.column()
703 col
.prop(self
, "Fillet_radius")
704 col
.prop(self
, "Fillet_Type", expand
=True)
707 def poll(cls
, context
):
708 return util
.Selected1OrMoreCurves()
710 def execute(self
, context
):
712 if bpy
.ops
.object.mode_set
.poll():
713 bpy
.ops
.object.mode_set(mode
='EDIT')
715 splines
= bpy
.context
.object.data
.splines
716 bpy
.ops
.curve
.spline_type_set(type='BEZIER')
718 bpy
.ops
.curve
.handle_type_set(type='VECTOR')
720 for spline
in splines
:
723 for p
in spline
.bezier_points
:
724 if p
.select_control_point
:
732 for spline
in splines
:
734 bezier_points
= spline
.bezier_points
735 n
= len(bezier_points
)
741 bpy
.ops
.curve
.select_all(action
='DESELECT')
743 if j
!= 0 and j
!= n
- 1:
744 bezier_points
[j
].select_control_point
= True
745 bezier_points
[j
+ 1].select_control_point
= True
746 bpy
.ops
.curve
.subdivide()
747 selected4
= [bezier_points
[j
- 1], bezier_points
[j
],
748 bezier_points
[j
+ 1], bezier_points
[j
+ 2]]
753 bezier_points
[j
].select_control_point
= True
754 bezier_points
[j
+ 1].select_control_point
= True
755 bpy
.ops
.curve
.subdivide()
756 selected4
= [bezier_points
[n
], bezier_points
[0],
757 bezier_points
[1], bezier_points
[2]]
762 bezier_points
[j
].select_control_point
= True
763 bezier_points
[j
- 1].select_control_point
= True
764 bpy
.ops
.curve
.subdivide()
765 selected4
= [bezier_points
[0], bezier_points
[n
],
766 bezier_points
[n
- 1], bezier_points
[n
- 2]]
768 selected4
[2].co
= selected4
[1].co
769 s1
= Vector(selected4
[0].co
) - Vector(selected4
[1].co
)
770 s2
= Vector(selected4
[3].co
) - Vector(selected4
[2].co
)
772 s11
= Vector(selected4
[1].co
) + s1
* self
.Fillet_radius
773 selected4
[1].co
= s11
775 s22
= Vector(selected4
[2].co
) + s2
* self
.Fillet_radius
776 selected4
[2].co
= s22
778 if self
.Fillet_Type
== 'Round':
780 selected4
[2].handle_right_type
= 'VECTOR'
781 selected4
[1].handle_left_type
= 'VECTOR'
782 selected4
[1].handle_right_type
= 'ALIGNED'
783 selected4
[2].handle_left_type
= 'ALIGNED'
785 selected4
[1].handle_right_type
= 'VECTOR'
786 selected4
[2].handle_left_type
= 'VECTOR'
787 selected4
[2].handle_right_type
= 'ALIGNED'
788 selected4
[1].handle_left_type
= 'ALIGNED'
789 if self
.Fillet_Type
== 'Chamfer':
790 selected4
[2].handle_right_type
= 'VECTOR'
791 selected4
[1].handle_left_type
= 'VECTOR'
792 selected4
[1].handle_right_type
= 'VECTOR'
793 selected4
[2].handle_left_type
= 'VECTOR'
798 # ------------------------------------------------------------
799 # BezierDivide Operator
801 class BezierDivide(bpy
.types
.Operator
):
802 bl_idname
= "curvetools.bezier_spline_divide"
803 bl_label
= "Bezier Spline Divide"
804 bl_description
= "Bezier Divide (enters edit mode) for Fillet Curves"
805 bl_options
= {'REGISTER', 'UNDO'}
807 # align_matrix for the invoke
808 align_matrix
: Matrix()
810 Bezier_t
: FloatProperty(
811 name
="t (0% - 100%)",
813 min=0.0, soft_min
=0.0,
814 max=100.0, soft_max
=100.0,
815 description
="t (0% - 100%)"
819 def poll(cls
, context
):
820 return util
.Selected1OrMoreCurves()
822 def execute(self
, context
):
824 if bpy
.ops
.object.mode_set
.poll():
825 bpy
.ops
.object.mode_set(mode
='EDIT')
827 splines
= bpy
.context
.object.data
.splines
829 for spline
in splines
:
830 bpy
.ops
.curve
.spline_type_set(type='BEZIER')
834 for p
in spline
.bezier_points
:
835 if p
.select_control_point
:
843 for spline
in splines
:
845 bezier_points
= spline
.bezier_points
846 n
= len(bezier_points
)
851 bpy
.ops
.curve
.select_all(action
='DESELECT')
853 if (j
in ii
) and (j
+ 1 in ii
):
854 bezier_points
[j
+ jn
].select_control_point
= True
855 bezier_points
[j
+ 1 + jn
].select_control_point
= True
856 h
= mathematics
.subdivide_cubic_bezier(
857 bezier_points
[j
+ jn
].co
, bezier_points
[j
+ jn
].handle_right
,
858 bezier_points
[j
+ 1 + jn
].handle_left
, bezier_points
[j
+ 1 + jn
].co
, self
.Bezier_t
/ 100
860 bpy
.ops
.curve
.subdivide(1)
861 bezier_points
[j
+ jn
].handle_right_type
= 'FREE'
862 bezier_points
[j
+ jn
].handle_right
= h
[0]
863 bezier_points
[j
+ 1 + jn
].co
= h
[2]
864 bezier_points
[j
+ 1 + jn
].handle_left_type
= 'FREE'
865 bezier_points
[j
+ 1 + jn
].handle_left
= h
[1]
866 bezier_points
[j
+ 1 + jn
].handle_right_type
= 'FREE'
867 bezier_points
[j
+ 1 + jn
].handle_right
= h
[3]
868 bezier_points
[j
+ 2 + jn
].handle_left_type
= 'FREE'
869 bezier_points
[j
+ 2 + jn
].handle_left
= h
[4]
872 if j
== n
- 1 and (0 in ii
) and spline
.use_cyclic_u
:
873 bezier_points
[j
+ jn
].select_control_point
= True
874 bezier_points
[0].select_control_point
= True
875 h
= mathematics
.subdivide_cubic_bezier(
876 bezier_points
[j
+ jn
].co
, bezier_points
[j
+ jn
].handle_right
,
877 bezier_points
[0].handle_left
, bezier_points
[0].co
, self
.Bezier_t
/ 100
879 bpy
.ops
.curve
.subdivide(1)
880 bezier_points
[j
+ jn
].handle_right_type
= 'FREE'
881 bezier_points
[j
+ jn
].handle_right
= h
[0]
882 bezier_points
[j
+ 1 + jn
].co
= h
[2]
883 bezier_points
[j
+ 1 + jn
].handle_left_type
= 'FREE'
884 bezier_points
[j
+ 1 + jn
].handle_left
= h
[1]
885 bezier_points
[j
+ 1 + jn
].handle_right_type
= 'FREE'
886 bezier_points
[j
+ 1 + jn
].handle_right
= h
[3]
887 bezier_points
[0].handle_left_type
= 'FREE'
888 bezier_points
[0].handle_left
= h
[4]
894 # ------------------------------------------------------------
895 # CurveScaleReset Operator
897 class CurveScaleReset(bpy
.types
.Operator
):
898 bl_idname
= "curvetools.scale_reset"
899 bl_label
= "Curve Scale Reset"
900 bl_description
= "Curve Scale Reset"
901 bl_options
= {'REGISTER', 'UNDO'}
904 def poll(cls
, context
):
905 return (context
.object is not None and
906 context
.object.type == 'CURVE')
908 def execute(self
, context
):
910 current_mode
= bpy
.context
.object.mode
912 bpy
.ops
.object.mode_set(mode
= 'OBJECT')
914 oldCurve
= context
.active_object
915 oldCurveName
= oldCurve
.name
917 bpy
.ops
.object.duplicate_move(OBJECT_OT_duplicate
=None, TRANSFORM_OT_translate
=None)
918 newCurve
= context
.active_object
919 newCurve
.data
.splines
.clear()
920 newCurve
.scale
= (1.0, 1.0, 1.0)
922 oldCurve
.select_set(True)
923 newCurve
.select_set(True)
924 bpy
.context
.view_layer
.objects
.active
= newCurve
925 bpy
.ops
.object.join()
927 joinCurve
= context
.active_object
928 joinCurve
.name
= oldCurveName
930 bpy
.ops
.object.mode_set (mode
= current_mode
)
934 # ------------------------------------------------------------
937 class Split(bpy
.types
.Operator
):
938 bl_idname
= "curvetools.split"
940 bl_options
= {'REGISTER', 'UNDO'}
943 def poll(cls
, context
):
944 return util
.Selected1OrMoreCurves()
946 def execute(self
, context
):
947 selected_Curves
= util
.GetSelectedCurves()
949 for curve
in selected_Curves
:
952 bezier_spline_points
= []
953 select_bezier_points
= {}
956 for spline
in curve
.data
.splines
:
957 if spline
.type == 'BEZIER':
959 select_bezier_points
[i_bp
] = [len(spline
.bezier_points
)]
960 for i
in range(len(spline
.bezier_points
)):
961 bezier_point
= spline
.bezier_points
[i
]
962 points
[i
]=[bezier_point
.co
[:], bezier_point
.handle_left
[:], bezier_point
.handle_right
[:]]
964 if spline
.bezier_points
[i
].select_control_point
:
965 select_bezier_points
[i_bp
].append(i
)
967 bezier_spline_points
.append(points
)
970 select_points
[i_p
] = [len(spline
.points
)]
971 for i
in range(len(spline
.points
)):
972 point
= spline
.points
[i
]
973 points
[i
]=[point
.co
[:], spline
.type]
974 if spline
.points
[i
].select
:
975 select_points
[i_p
].append(i
)
977 spline_points
.append(points
)
979 curve
.data
.splines
.clear()
981 for key
in select_bezier_points
:
985 if select_bezier_points
[key
][-1] == select_bezier_points
[key
][0]-1:
986 select_bezier_points
[key
].pop()
988 for i
in select_bezier_points
[key
][1:]+[select_bezier_points
[key
][0]-1]:
990 spline
= curve
.data
.splines
.new('BEZIER')
991 spline
.bezier_points
.add(i
-num
)
993 for j
in range(num
, i
):
994 bezier_point
= spline
.bezier_points
[j
-num
]
996 bezier_point
.co
= bezier_spline_points
[key
][j
][0]
997 bezier_point
.handle_left
= bezier_spline_points
[key
][j
][1]
998 bezier_point
.handle_right
= bezier_spline_points
[key
][j
][2]
999 bezier_point
= spline
.bezier_points
[-1]
1000 bezier_point
.co
= bezier_spline_points
[key
][i
][0]
1001 bezier_point
.handle_left
= bezier_spline_points
[key
][i
][1]
1002 bezier_point
.handle_right
= bezier_spline_points
[key
][i
][2]
1005 for key
in select_points
:
1009 if select_points
[key
][-1] == select_points
[key
][0]-1:
1010 select_points
[key
].pop()
1012 for i
in select_points
[key
][1:]+[select_points
[key
][0]-1]:
1014 spline
= curve
.data
.splines
.new(spline_points
[key
][i
][1])
1015 spline
.points
.add(i
-num
)
1017 for j
in range(num
, i
):
1018 point
= spline
.points
[j
-num
]
1020 point
.co
= spline_points
[key
][j
][0]
1021 point
= spline
.points
[-1]
1022 point
.co
= spline_points
[key
][i
][0]
1027 class SeparateOutline(bpy
.types
.Operator
):
1028 bl_idname
= "curvetools.sep_outline"
1029 bl_label
= "Separate Outline"
1030 bl_options
= {'REGISTER', 'UNDO'}
1031 bl_description
= "Makes 'Outline' separate mesh"
1034 def poll(cls
, context
):
1035 return util
.Selected1OrMoreCurves()
1037 def execute(self
, context
):
1038 bpy
.ops
.object.mode_set(mode
= 'EDIT')
1039 bpy
.ops
.curve
.separate()
1043 class CurveBoolean(bpy
.types
.Operator
):
1044 bl_idname
= "curvetools.bezier_curve_boolean"
1045 bl_description
= "Curve Boolean"
1046 bl_label
= "Curve Boolean"
1047 bl_options
= {'REGISTER', 'UNDO'}
1049 operation
: bpy
.props
.EnumProperty(name
='Type', items
=[
1050 ('UNION', 'Union', 'Boolean OR', 0),
1051 ('INTERSECTION', 'Intersection', 'Boolean AND', 1),
1052 ('DIFFERENCE', 'Difference', 'Active minus Selected', 2),
1054 number
: IntProperty(
1055 name
="Spline Number",
1058 description
="Spline Number"
1062 def poll(cls
, context
):
1063 return util
.Selected1OrMoreCurves()
1065 def draw(self
, context
):
1066 layout
= self
.layout
1069 col
= layout
.column()
1070 col
.prop(self
, "operation")
1071 if self
.operation
== 'DIFFERENCE':
1072 col
.prop(self
, "number")
1074 def execute(self
, context
):
1075 current_mode
= bpy
.context
.object.mode
1077 if bpy
.ops
.object.mode_set
.poll():
1078 bpy
.ops
.object.mode_set(mode
= 'OBJECT')
1080 selected_Curves
= util
.GetSelectedCurves()
1081 len_selected_curves
= len(selected_Curves
)
1082 if len_selected_curves
< 2:
1088 for iCurve
in range(0, len_selected_curves
):
1089 len_splines
= len(selected_Curves
[iCurve
].data
.splines
)
1090 max_number
+= len_splines
1092 if self
.number
< min_number
:
1093 self
.number
= min_number
1094 if self
.number
> max_number
:
1095 self
.number
= max_number
1100 for iCurve
in range(0, len_selected_curves
):
1101 len_splines
= len(selected_Curves
[iCurve
].data
.splines
)
1102 for iSpline
in range(0, len_splines
):
1103 if j
== self
.number
:
1104 first_curve
= iCurve
1105 first_spline
= iSpline
1108 bpy
.ops
.object.select_all(action
='DESELECT')
1110 spline1
= selected_Curves
[first_curve
].data
.splines
[first_spline
]
1111 matrix_world1
= selected_Curves
[first_curve
].matrix_world
1113 len_spline1
= len(spline1
.bezier_points
)
1115 dataCurve
= bpy
.data
.curves
.new(self
.operation
, type='CURVE')
1116 dataCurve
.dimensions
= '2D'
1117 newSpline1
= dataCurve
.splines
.new(type='BEZIER')
1118 newSpline1
.use_cyclic_u
= True
1119 newSpline1
.bezier_points
.add(len_spline1
- 1)
1120 for n
in range(0, len_spline1
):
1121 newSpline1
.bezier_points
[n
].co
= matrix_world1
@ spline1
.bezier_points
[n
].co
1122 newSpline1
.bezier_points
[n
].handle_left_type
= spline1
.bezier_points
[n
].handle_left_type
1123 newSpline1
.bezier_points
[n
].handle_left
= matrix_world1
@ spline1
.bezier_points
[n
].handle_left
1124 newSpline1
.bezier_points
[n
].handle_right_type
= spline1
.bezier_points
[n
].handle_right_type
1125 newSpline1
.bezier_points
[n
].handle_right
= matrix_world1
@ spline1
.bezier_points
[n
].handle_right
1127 Curve
= object_utils
.object_data_add(context
, dataCurve
)
1128 bpy
.context
.view_layer
.objects
.active
= Curve
1129 Curve
.select_set(True)
1130 Curve
.location
= (0.0, 0.0, 0.0)
1133 for iCurve
in range(0, len_selected_curves
):
1134 matrix_world
= selected_Curves
[iCurve
].matrix_world
1135 len_splines
= len(selected_Curves
[iCurve
].data
.splines
)
1136 for iSpline
in range(0, len_splines
):
1137 if iCurve
== first_curve
and iSpline
== first_spline
:
1139 spline
= selected_Curves
[iCurve
].data
.splines
[iSpline
]
1140 len_spline
= len(spline
.bezier_points
)
1141 newSpline
= dataCurve
.splines
.new(type='BEZIER')
1142 newSpline
.use_cyclic_u
= True
1143 newSpline
.bezier_points
.add(len_spline
- 1)
1144 for n
in range(0, len_spline
):
1145 newSpline
.bezier_points
[n
].co
= matrix_world
@ spline
.bezier_points
[n
].co
1146 newSpline
.bezier_points
[n
].handle_left_type
= spline
.bezier_points
[n
].handle_left_type
1147 newSpline
.bezier_points
[n
].handle_left
= matrix_world
@ spline
.bezier_points
[n
].handle_left
1148 newSpline
.bezier_points
[n
].handle_right_type
= spline
.bezier_points
[n
].handle_right_type
1149 newSpline
.bezier_points
[n
].handle_right
= matrix_world
@ spline
.bezier_points
[n
].handle_right
1151 bpy
.ops
.object.mode_set(mode
= 'EDIT')
1152 bpy
.ops
.curve
.select_all(action
='SELECT')
1153 splines
= internal
.getSelectedSplines(True, True)
1154 if len(splines
) < 2:
1156 splineA
= splines
[0]
1157 splineB
= splines
[1]
1158 dataCurve
.splines
.active
= newSpline1
1160 if not internal
.bezierBooleanGeometry(splineA
, splineB
, self
.operation
):
1161 self
.report({'WARNING'}, 'Invalid selection.')
1162 return {'CANCELLED'}
1166 bpy
.ops
.object.mode_set(mode
= 'EDIT')
1167 bpy
.ops
.curve
.select_all(action
='SELECT')
1171 # ----------------------------
1172 # Set first points operator
1173 class SetFirstPoints(bpy
.types
.Operator
):
1174 bl_idname
= "curvetools.set_first_points"
1175 bl_label
= "Set first points"
1176 bl_description
= "Set the selected points as the first point of each spline"
1177 bl_options
= {'REGISTER', 'UNDO'}
1180 def poll(cls
, context
):
1181 return util
.Selected1OrMoreCurves()
1183 def execute(self
, context
):
1184 splines_to_invert
= []
1186 curve
= bpy
.context
.object
1188 bpy
.ops
.object.mode_set('INVOKE_REGION_WIN', mode
='EDIT')
1190 # Check non-cyclic splines to invert
1191 for i
in range(len(curve
.data
.splines
)):
1192 b_points
= curve
.data
.splines
[i
].bezier_points
1194 if i
not in self
.cyclic_splines
: # Only for non-cyclic splines
1195 if b_points
[len(b_points
) - 1].select_control_point
:
1196 splines_to_invert
.append(i
)
1198 # Reorder points of cyclic splines, and set all handles to "Automatic"
1200 # Check first selected point
1201 cyclic_splines_new_first_pt
= {}
1202 for i
in self
.cyclic_splines
:
1203 sp
= curve
.data
.splines
[i
]
1205 for t
in range(len(sp
.bezier_points
)):
1206 bp
= sp
.bezier_points
[t
]
1207 if bp
.select_control_point
or bp
.select_right_handle
or bp
.select_left_handle
:
1208 cyclic_splines_new_first_pt
[i
] = t
1209 break # To take only one if there are more
1212 for spline_idx
in cyclic_splines_new_first_pt
:
1213 sp
= curve
.data
.splines
[spline_idx
]
1215 spline_old_coords
= []
1216 for bp_old
in sp
.bezier_points
:
1217 coords
= (bp_old
.co
[0], bp_old
.co
[1], bp_old
.co
[2])
1219 left_handle_type
= str(bp_old
.handle_left_type
)
1220 left_handle_length
= float(bp_old
.handle_left
.length
)
1222 float(bp_old
.handle_left
.x
),
1223 float(bp_old
.handle_left
.y
),
1224 float(bp_old
.handle_left
.z
)
1226 right_handle_type
= str(bp_old
.handle_right_type
)
1227 right_handle_length
= float(bp_old
.handle_right
.length
)
1228 right_handle_xyz
= (
1229 float(bp_old
.handle_right
.x
),
1230 float(bp_old
.handle_right
.y
),
1231 float(bp_old
.handle_right
.z
)
1233 spline_old_coords
.append(
1234 [coords
, left_handle_type
,
1235 right_handle_type
, left_handle_length
,
1236 right_handle_length
, left_handle_xyz
,
1240 for t
in range(len(sp
.bezier_points
)):
1241 bp
= sp
.bezier_points
1243 if t
+ cyclic_splines_new_first_pt
[spline_idx
] + 1 <= len(bp
) - 1:
1244 new_index
= t
+ cyclic_splines_new_first_pt
[spline_idx
] + 1
1246 new_index
= t
+ cyclic_splines_new_first_pt
[spline_idx
] + 1 - len(bp
)
1248 bp
[t
].co
= Vector(spline_old_coords
[new_index
][0])
1250 bp
[t
].handle_left
.length
= spline_old_coords
[new_index
][3]
1251 bp
[t
].handle_right
.length
= spline_old_coords
[new_index
][4]
1253 bp
[t
].handle_left_type
= "FREE"
1254 bp
[t
].handle_right_type
= "FREE"
1256 bp
[t
].handle_left
.x
= spline_old_coords
[new_index
][5][0]
1257 bp
[t
].handle_left
.y
= spline_old_coords
[new_index
][5][1]
1258 bp
[t
].handle_left
.z
= spline_old_coords
[new_index
][5][2]
1260 bp
[t
].handle_right
.x
= spline_old_coords
[new_index
][6][0]
1261 bp
[t
].handle_right
.y
= spline_old_coords
[new_index
][6][1]
1262 bp
[t
].handle_right
.z
= spline_old_coords
[new_index
][6][2]
1264 bp
[t
].handle_left_type
= spline_old_coords
[new_index
][1]
1265 bp
[t
].handle_right_type
= spline_old_coords
[new_index
][2]
1267 # Invert the non-cyclic splines designated above
1268 for i
in range(len(splines_to_invert
)):
1269 bpy
.ops
.curve
.select_all('INVOKE_REGION_WIN', action
='DESELECT')
1271 bpy
.ops
.object.editmode_toggle('INVOKE_REGION_WIN')
1272 curve
.data
.splines
[splines_to_invert
[i
]].bezier_points
[0].select_control_point
= True
1273 bpy
.ops
.object.editmode_toggle('INVOKE_REGION_WIN')
1275 bpy
.ops
.curve
.switch_direction()
1277 bpy
.ops
.curve
.select_all('INVOKE_REGION_WIN', action
='DESELECT')
1279 # Keep selected the first vert of each spline
1280 bpy
.ops
.object.editmode_toggle('INVOKE_REGION_WIN')
1281 for i
in range(len(curve
.data
.splines
)):
1282 if not curve
.data
.splines
[i
].use_cyclic_u
:
1283 bp
= curve
.data
.splines
[i
].bezier_points
[0]
1285 bp
= curve
.data
.splines
[i
].bezier_points
[
1286 len(curve
.data
.splines
[i
].bezier_points
) - 1
1289 bp
.select_control_point
= True
1290 bp
.select_right_handle
= True
1291 bp
.select_left_handle
= True
1293 bpy
.ops
.object.editmode_toggle('INVOKE_REGION_WIN')
1297 def invoke(self
, context
, event
):
1298 curve
= bpy
.context
.object
1300 # Check if all curves are Bezier, and detect which ones are cyclic
1301 self
.cyclic_splines
= []
1302 for i
in range(len(curve
.data
.splines
)):
1303 if curve
.data
.splines
[i
].type != "BEZIER":
1304 self
.report({'WARNING'}, "All splines must be Bezier type")
1306 return {'CANCELLED'}
1308 if curve
.data
.splines
[i
].use_cyclic_u
:
1309 self
.cyclic_splines
.append(i
)
1311 self
.execute(context
)
1312 self
.report({'INFO'}, "First points have been set")
1318 bpy
.utils
.register_class(operators
)
1322 bpy
.utils
.unregister_class(operators
)
1324 if __name__
== "__main__":
1329 OperatorCurveLength
,
1330 OperatorSplinesInfo
,
1331 OperatorSegmentsInfo
,
1332 OperatorOriginToSpline0Start
,
1333 OperatorIntersectCurves
,
1335 OperatorSweepCurves
,
1337 OperatorSplinesSetResolution
,
1338 OperatorSplinesRemoveZeroSegment
,
1339 OperatorSplinesRemoveShort
,
1340 OperatorSplinesJoinNeighbouring
,
1341 ConvertSelectedFacesToBezier
,
1342 ConvertBezierToSurface
,