1 # SPDX-License-Identifier: GPL-2.0-or-later
7 from bpy
.props
import *
8 from bpy_extras
import object_utils
, view3d_utils
9 from mathutils
import *
12 from . import properties
14 from . import intersections
16 from . import surfaces
17 from . import mathematics
18 from . import internal
22 class OperatorCurveInfo(bpy
.types
.Operator
):
23 bl_idname
= "curvetools.operatorcurveinfo"
25 bl_description
= "Displays general info about the active/selected curve"
29 def poll(cls
, context
):
30 return util
.Selected1Curve()
33 def execute(self
, context
):
34 curve
= curves
.Curve(context
.active_object
)
36 nrSplines
= len(curve
.splines
)
39 for spline
in curve
.splines
:
40 nrSegments
+= spline
.nrSegments
41 if spline
.nrSegments
< 1: nrEmptySplines
+= 1
44 self
.report({'INFO'}, "nrSplines: %d; nrSegments: %d; nrEmptySplines: %d" % (nrSplines
, nrSegments
, nrEmptySplines
))
50 class OperatorCurveLength(bpy
.types
.Operator
):
51 bl_idname
= "curvetools.operatorcurvelength"
53 bl_description
= "Calculates the length of the active/selected curve"
57 def poll(cls
, context
):
58 return util
.Selected1Curve()
61 def execute(self
, context
):
62 curve
= curves
.Curve(context
.active_object
)
64 context
.scene
.curvetools
.CurveLength
= curve
.length
70 class OperatorSplinesInfo(bpy
.types
.Operator
):
71 bl_idname
= "curvetools.operatorsplinesinfo"
73 bl_description
= "Displays general info about the splines of the active/selected curve"
77 def poll(cls
, context
):
78 return util
.Selected1Curve()
81 def execute(self
, context
):
82 curve
= curves
.Curve(context
.active_object
)
83 nrSplines
= len(curve
.splines
)
86 print("OperatorSplinesInfo:", "nrSplines:", nrSplines
)
89 for iSpline
, spline
in enumerate(curve
.splines
):
90 print("--", "spline %d of %d: nrSegments: %d" % (iSpline
+ 1, nrSplines
, spline
.nrSegments
))
92 if spline
.nrSegments
< 1:
94 print("--", "--", "## WARNING: spline has no segments and will therefor be ignored in any further calculations")
97 self
.report({'INFO'}, "nrSplines: %d; nrEmptySplines: %d" % (nrSplines
, nrEmptySplines
) + " -- more info: see console")
103 class OperatorSegmentsInfo(bpy
.types
.Operator
):
104 bl_idname
= "curvetools.operatorsegmentsinfo"
106 bl_description
= "Displays general info about the segments of the active/selected curve"
110 def poll(cls
, context
):
111 return util
.Selected1Curve()
114 def execute(self
, context
):
115 curve
= curves
.Curve(context
.active_object
)
116 nrSplines
= len(curve
.splines
)
120 print("OperatorSegmentsInfo:", "nrSplines:", nrSplines
)
123 for iSpline
, spline
in enumerate(curve
.splines
):
124 nrSegmentsSpline
= spline
.nrSegments
125 print("--", "spline %d of %d: nrSegments: %d" % (iSpline
+ 1, nrSplines
, nrSegmentsSpline
))
127 if nrSegmentsSpline
< 1:
129 print("--", "--", "## WARNING: spline has no segments and will therefor be ignored in any further calculations")
132 for iSegment
, segment
in enumerate(spline
.segments
):
133 print("--", "--", "segment %d of %d coefficients:" % (iSegment
+ 1, nrSegmentsSpline
))
134 print("--", "--", "--", "C0: %.6f, %.6f, %.6f" % (segment
.coeff0
.x
, segment
.coeff0
.y
, segment
.coeff0
.z
))
136 nrSegments
+= nrSegmentsSpline
138 self
.report({'INFO'}, "nrSplines: %d; nrSegments: %d; nrEmptySplines: %d" % (nrSplines
, nrSegments
, nrEmptySplines
))
144 class OperatorOriginToSpline0Start(bpy
.types
.Operator
):
145 bl_idname
= "curvetools.operatororigintospline0start"
146 bl_label
= "OriginToSpline0Start"
147 bl_description
= "Sets the origin of the active/selected curve to the starting point of the (first) spline. Nice for curve modifiers"
148 bl_options
= {'UNDO'}
152 def poll(cls
, context
):
153 return util
.Selected1Curve()
156 def execute(self
, context
):
159 blCurve
= context
.active_object
160 blSpline
= blCurve
.data
.splines
[0]
161 newOrigin
= blCurve
.matrix_world
@ blSpline
.bezier_points
[0].co
163 origOrigin
= bpy
.context
.scene
.cursor
.location
.copy()
164 self
.report({'INFO'}, "origOrigin: %.6f, %.6f, %.6f" % (origOrigin
.x
, origOrigin
.y
, origOrigin
.z
))
165 self
.report({'INFO'}, "newOrigin: %.6f, %.6f, %.6f" % (newOrigin
.x
, newOrigin
.y
, newOrigin
.z
))
167 current_mode
= bpy
.context
.object.mode
169 bpy
.ops
.object.mode_set(mode
= 'OBJECT')
170 bpy
.context
.scene
.cursor
.location
= newOrigin
171 bpy
.ops
.object.origin_set(type='ORIGIN_CURSOR')
172 bpy
.context
.scene
.cursor
.location
= origOrigin
174 bpy
.ops
.object.mode_set (mode
= current_mode
)
182 class OperatorIntersectCurves(bpy
.types
.Operator
):
183 bl_idname
= "curvetools.operatorintersectcurves"
184 bl_label
= "Intersect"
185 bl_description
= "Intersects selected curves"
186 bl_options
= {'UNDO'}
190 def poll(cls
, context
):
191 return util
.Selected2OrMoreCurves()
194 def execute(self
, context
):
195 print("### TODO: OperatorIntersectcurves.execute()")
197 algo
= context
.scene
.curvetools
.IntersectCurvesAlgorithm
198 print("-- algo:", algo
)
201 mode
= context
.scene
.curvetools
.IntersectCurvesMode
202 print("-- mode:", mode
)
203 # if mode == 'Split':
204 # self.report({'WARNING'}, "'Split' mode is not implemented yet -- <<STOPPING>>")
205 # return {'CANCELLED'}
207 affect
= context
.scene
.curvetools
.IntersectCurvesAffect
208 print("-- affect:", affect
)
210 selected_objects
= context
.selected_objects
211 lenodjs
= len(selected_objects
)
212 print('lenodjs:', lenodjs
)
213 for i
in range(0, lenodjs
):
214 for j
in range(0, lenodjs
):
216 bpy
.ops
.object.select_all(action
='DESELECT')
217 selected_objects
[i
].select_set(True)
218 selected_objects
[j
].select_set(True)
220 if selected_objects
[i
].type == 'CURVE' and selected_objects
[j
].type == 'CURVE':
221 curveIntersector
= intersections
.CurvesIntersector
.FromSelection()
222 rvIntersectionNrs
= curveIntersector
.CalcAndApplyIntersections()
224 self
.report({'INFO'}, "Active curve points: %d; other curve points: %d" % (rvIntersectionNrs
[0], rvIntersectionNrs
[1]))
226 for obj
in selected_objects
:
231 # ------------------------------------------------------------
234 class OperatorLoftCurves(bpy
.types
.Operator
):
235 bl_idname
= "curvetools.operatorloftcurves"
237 bl_description
= "Lofts selected curves"
238 bl_options
= {'UNDO'}
242 def poll(cls
, context
):
243 return util
.Selected2Curves()
246 def execute(self
, context
):
247 #print("### TODO: OperatorLoftcurves.execute()")
249 loftedSurface
= surfaces
.LoftedSurface
.FromSelection()
250 loftedSurface
.AddToScene()
252 self
.report({'INFO'}, "OperatorLoftcurves.execute()")
257 # ------------------------------------------------------------
258 # OperatorSweepCurves
260 class OperatorSweepCurves(bpy
.types
.Operator
):
261 bl_idname
= "curvetools.operatorsweepcurves"
263 bl_description
= "Sweeps the active curve along to other curve (rail)"
264 bl_options
= {'UNDO'}
268 def poll(cls
, context
):
269 return util
.Selected2Curves()
272 def execute(self
, context
):
273 #print("### TODO: OperatorSweepcurves.execute()")
275 sweptSurface
= surfaces
.SweptSurface
.FromSelection()
276 sweptSurface
.AddToScene()
278 self
.report({'INFO'}, "OperatorSweepcurves.execute()")
286 class OperatorBirail(bpy
.types
.Operator
):
287 bl_idname
= "curvetools.operatorbirail"
289 bl_description
= "Generates a birailed surface from 3 selected curves -- in order: rail1, rail2 and profile"
290 bl_options
= {'UNDO'}
294 def poll(cls
, context
):
295 return util
.Selected3Curves()
298 def execute(self
, context
):
299 birailedSurface
= surfaces
.BirailedSurface
.FromSelection()
300 birailedSurface
.AddToScene()
302 self
.report({'INFO'}, "OperatorBirail.execute()")
308 # 1 OR MORE CURVES SELECTED
309 # #########################
310 class OperatorSplinesSetResolution(bpy
.types
.Operator
):
311 bl_idname
= "curvetools.operatorsplinessetresolution"
312 bl_label
= "SplinesSetResolution"
313 bl_description
= "Sets the resolution of all splines"
314 bl_options
= {'UNDO'}
318 def poll(cls
, context
):
319 return util
.Selected1OrMoreCurves()
322 def execute(self
, context
):
323 splRes
= context
.scene
.curvetools
.SplineResolution
324 selCurves
= util
.GetSelectedCurves()
326 for blCurve
in selCurves
:
327 for spline
in blCurve
.data
.splines
:
328 spline
.resolution_u
= splRes
332 # ------------------------------------------------------------
333 # OperatorSplinesRemoveZeroSegment
335 class OperatorSplinesRemoveZeroSegment(bpy
.types
.Operator
):
336 bl_idname
= "curvetools.operatorsplinesremovezerosegment"
337 bl_label
= "SplinesRemoveZeroSegment"
338 bl_description
= "Removes splines with no segments -- they seem to creep up, sometimes"
339 bl_options
= {'UNDO'}
343 def poll(cls
, context
):
344 return util
.Selected1OrMoreCurves()
347 def execute(self
, context
):
348 selCurves
= util
.GetSelectedCurves()
350 for blCurve
in selCurves
:
351 curve
= curves
.Curve(blCurve
)
352 nrSplines
= curve
.nrSplines
355 for spline
in curve
.splines
:
356 if len(spline
.segments
) < 1: splinesToRemove
.append(spline
)
357 nrRemovedSplines
= len(splinesToRemove
)
359 for spline
in splinesToRemove
: curve
.splines
.remove(spline
)
361 if nrRemovedSplines
> 0: curve
.RebuildInScene()
363 self
.report({'INFO'}, "Removed %d of %d splines" % (nrRemovedSplines
, nrSplines
))
367 # ------------------------------------------------------------
368 # OperatorSplinesRemoveShort
370 class OperatorSplinesRemoveShort(bpy
.types
.Operator
):
371 bl_idname
= "curvetools.operatorsplinesremoveshort"
372 bl_label
= "SplinesRemoveShort"
373 bl_description
= "Removes splines with a length smaller than the threshold"
374 bl_options
= {'UNDO'}
378 def poll(cls
, context
):
379 return util
.Selected1OrMoreCurves()
382 def execute(self
, context
):
383 threshold
= context
.scene
.curvetools
.SplineRemoveLength
384 selCurves
= util
.GetSelectedCurves()
386 for blCurve
in selCurves
:
387 curve
= curves
.Curve(blCurve
)
388 nrSplines
= curve
.nrSplines
390 nrRemovedSplines
= curve
.RemoveShortSplines(threshold
)
391 if nrRemovedSplines
> 0: curve
.RebuildInScene()
393 self
.report({'INFO'}, "Removed %d of %d splines" % (nrRemovedSplines
, nrSplines
))
397 # ------------------------------------------------------------
398 # OperatorSplinesJoinNeighbouring
400 class OperatorSplinesJoinNeighbouring(bpy
.types
.Operator
):
401 bl_idname
= "curvetools.operatorsplinesjoinneighbouring"
402 bl_label
= "SplinesJoinNeighbouring"
403 bl_description
= "Joins neighbouring splines within a distance smaller than the threshold"
404 bl_options
= {'UNDO'}
408 def poll(cls
, context
):
409 return util
.Selected1OrMoreCurves()
412 def execute(self
, context
):
413 selCurves
= util
.GetSelectedCurves()
415 for blCurve
in selCurves
:
416 curve
= curves
.Curve(blCurve
)
417 nrSplines
= curve
.nrSplines
419 threshold
= context
.scene
.curvetools
.SplineJoinDistance
420 startEnd
= context
.scene
.curvetools
.SplineJoinStartEnd
421 mode
= context
.scene
.curvetools
.SplineJoinMode
423 nrJoins
= curve
.JoinNeighbouringSplines(startEnd
, threshold
, mode
)
424 if nrJoins
> 0: curve
.RebuildInScene()
426 self
.report({'INFO'}, "Applied %d joins on %d splines; resulting nrSplines: %d" % (nrJoins
, nrSplines
, curve
.nrSplines
))
430 # ------------------------------------------------------------
433 def SurfaceFromBezier(surfacedata
, points
, center
):
435 len_points
= len(points
) - 1
437 if len_points
% 2 == 0:
438 h
= mathematics
.subdivide_cubic_bezier(
439 points
[len_points
].co
, points
[len_points
].handle_right
,
440 points
[0].handle_left
, points
[0].co
, 0.5
443 len_points
= len(points
) - 1
444 points
[len_points
- 1].handle_right
= h
[0]
445 points
[len_points
].handle_left
= h
[1]
446 points
[len_points
].co
= h
[2]
447 points
[len_points
].handle_right
= h
[3]
448 points
[0].handle_left
= h
[4]
450 half
= round((len_points
+ 1)/2) - 1
452 surfacespline1
= surfacedata
.splines
.new(type='NURBS')
453 surfacespline1
.points
.add(3)
454 surfacespline1
.points
[0].co
= [points
[0].co
.x
, points
[0].co
.y
, points
[0].co
.z
, 1]
455 surfacespline1
.points
[1].co
= [points
[0].handle_left
.x
, points
[0].handle_left
.y
, points
[0].handle_left
.z
, 1]
456 surfacespline1
.points
[2].co
= [points
[len_points
].handle_right
.x
,points
[len_points
].handle_right
.y
, points
[len_points
].handle_right
.z
, 1]
457 surfacespline1
.points
[3].co
= [points
[len_points
].co
.x
, points
[len_points
].co
.y
, points
[len_points
].co
.z
, 1]
458 for p
in surfacespline1
.points
:
460 surfacespline1
.use_endpoint_u
= True
461 surfacespline1
.use_endpoint_v
= True
463 for i
in range(0, half
):
467 surfacespline2
= surfacedata
.splines
.new(type='NURBS')
468 surfacespline2
.points
.add(3)
469 surfacespline2
.points
[0].co
= [points
[i
].co
.x
, points
[i
].co
.y
, points
[i
].co
.z
, 1]
470 surfacespline2
.points
[1].co
= [(points
[i
].co
.x
+ points
[len_points
- i
].co
.x
)/2,
471 (points
[i
].co
.y
+ points
[len_points
- i
].co
.y
)/2,
472 (points
[i
].co
.z
+ points
[len_points
- i
].co
.z
)/2, 1]
473 surfacespline2
.points
[2].co
= [(points
[len_points
- i
].co
.x
+ points
[i
].co
.x
)/2,
474 (points
[len_points
- i
].co
.y
+ points
[i
].co
.y
)/2,
475 (points
[len_points
- i
].co
.z
+ points
[i
].co
.z
)/2, 1]
476 surfacespline2
.points
[3].co
= [points
[len_points
- i
].co
.x
, points
[len_points
- i
].co
.y
, points
[len_points
- i
].co
.z
, 1]
477 for p
in surfacespline2
.points
:
479 surfacespline2
.use_endpoint_u
= True
480 surfacespline2
.use_endpoint_v
= True
483 surfacespline3
= surfacedata
.splines
.new(type='NURBS')
484 surfacespline3
.points
.add(3)
485 surfacespline3
.points
[0].co
= [points
[i
].handle_right
.x
, points
[i
].handle_right
.y
, points
[i
].handle_right
.z
, 1]
486 surfacespline3
.points
[1].co
= [(points
[i
].handle_right
.x
+ points
[len_points
- i
].handle_left
.x
)/2,
487 (points
[i
].handle_right
.y
+ points
[len_points
- i
].handle_left
.y
)/2,
488 (points
[i
].handle_right
.z
+ points
[len_points
- i
].handle_left
.z
)/2, 1]
489 surfacespline3
.points
[2].co
= [(points
[len_points
- i
].handle_left
.x
+ points
[i
].handle_right
.x
)/2,
490 (points
[len_points
- i
].handle_left
.y
+ points
[i
].handle_right
.y
)/2,
491 (points
[len_points
- i
].handle_left
.z
+ points
[i
].handle_right
.z
)/2, 1]
492 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]
493 for p
in surfacespline3
.points
:
495 surfacespline3
.use_endpoint_u
= True
496 surfacespline3
.use_endpoint_v
= True
499 surfacespline4
= surfacedata
.splines
.new(type='NURBS')
500 surfacespline4
.points
.add(3)
501 surfacespline4
.points
[0].co
= [points
[i
+ 1].handle_left
.x
, points
[i
+ 1].handle_left
.y
, points
[i
+ 1].handle_left
.z
, 1]
502 surfacespline4
.points
[1].co
= [(points
[i
+ 1].handle_left
.x
+ points
[len_points
- i
- 1].handle_right
.x
)/2,
503 (points
[i
+ 1].handle_left
.y
+ points
[len_points
- i
- 1].handle_right
.y
)/2,
504 (points
[i
+ 1].handle_left
.z
+ points
[len_points
- i
- 1].handle_right
.z
)/2, 1]
505 surfacespline4
.points
[2].co
= [(points
[len_points
- i
- 1].handle_right
.x
+ points
[i
+ 1].handle_left
.x
)/2,
506 (points
[len_points
- i
- 1].handle_right
.y
+ points
[i
+ 1].handle_left
.y
)/2,
507 (points
[len_points
- i
- 1].handle_right
.z
+ points
[i
+ 1].handle_left
.z
)/2, 1]
508 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]
509 for p
in surfacespline4
.points
:
511 surfacespline4
.use_endpoint_u
= True
512 surfacespline4
.use_endpoint_v
= True
516 surfacespline5
= surfacedata
.splines
.new(type='NURBS')
517 surfacespline5
.points
.add(3)
518 surfacespline5
.points
[0].co
= [points
[i
+ 1].co
.x
, points
[i
+ 1].co
.y
, points
[i
+ 1].co
.z
, 1]
519 surfacespline5
.points
[1].co
= [(points
[i
+ 1].co
.x
+ points
[len_points
- i
- 1].co
.x
)/2,
520 (points
[i
+ 1].co
.y
+ points
[len_points
- i
- 1].co
.y
)/2,
521 (points
[i
+ 1].co
.z
+ points
[len_points
- i
- 1].co
.z
)/2, 1]
522 surfacespline5
.points
[2].co
= [(points
[len_points
- i
- 1].co
.x
+ points
[i
+ 1].co
.x
)/2,
523 (points
[len_points
- i
- 1].co
.y
+ points
[i
+ 1].co
.y
)/2,
524 (points
[len_points
- i
- 1].co
.z
+ points
[i
+ 1].co
.z
)/2, 1]
525 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]
526 for p
in surfacespline5
.points
:
528 surfacespline5
.use_endpoint_u
= True
529 surfacespline5
.use_endpoint_v
= True
532 surfacespline6
= surfacedata
.splines
.new(type='NURBS')
533 surfacespline6
.points
.add(3)
534 surfacespline6
.points
[0].co
= [points
[half
].co
.x
, points
[half
].co
.y
, points
[half
].co
.z
, 1]
535 surfacespline6
.points
[1].co
= [points
[half
].handle_right
.x
, points
[half
].handle_right
.y
, points
[half
].handle_right
.z
, 1]
536 surfacespline6
.points
[2].co
= [points
[half
+1].handle_left
.x
, points
[half
+1].handle_left
.y
, points
[half
+1].handle_left
.z
, 1]
537 surfacespline6
.points
[3].co
= [points
[half
+1].co
.x
, points
[half
+1].co
.y
, points
[half
+1].co
.z
, 1]
538 for p
in surfacespline6
.points
:
540 surfacespline6
.use_endpoint_u
= True
541 surfacespline6
.use_endpoint_v
= True
543 bpy
.ops
.object.mode_set(mode
= 'EDIT')
544 bpy
.ops
.curve
.make_segment()
546 for s
in surfacedata
.splines
:
554 # ------------------------------------------------------------
555 # Convert selected faces to Bezier
557 class ConvertSelectedFacesToBezier(bpy
.types
.Operator
):
558 bl_idname
= "curvetools.convert_selected_face_to_bezier"
559 bl_label
= "Convert selected faces to Bezier"
560 bl_description
= "Convert selected faces to Bezier"
561 bl_options
= {'REGISTER', 'UNDO'}
564 def poll(cls
, context
):
565 return util
.Selected1Mesh()
567 def execute(self
, context
):
569 bpy
.ops
.object.mode_set(mode
= 'OBJECT')
570 active_object
= context
.active_object
571 meshdata
= active_object
.data
572 curvedata
= bpy
.data
.curves
.new('Curve' + active_object
.name
, type='CURVE')
573 curveobject
= object_utils
.object_data_add(context
, curvedata
)
574 curvedata
.dimensions
= '3D'
576 for poly
in meshdata
.polygons
:
578 newSpline
= curvedata
.splines
.new(type='BEZIER')
579 newSpline
.use_cyclic_u
= True
580 newSpline
.bezier_points
.add(poly
.loop_total
- 1)
582 for loop_index
in range(poly
.loop_start
, poly
.loop_start
+ poly
.loop_total
):
583 newSpline
.bezier_points
[npoint
].co
= meshdata
.vertices
[meshdata
.loops
[loop_index
].vertex_index
].co
584 newSpline
.bezier_points
[npoint
].handle_left_type
= 'VECTOR'
585 newSpline
.bezier_points
[npoint
].handle_right_type
= 'VECTOR'
586 newSpline
.bezier_points
[npoint
].select_control_point
= True
587 newSpline
.bezier_points
[npoint
].select_left_handle
= True
588 newSpline
.bezier_points
[npoint
].select_right_handle
= True
593 # ------------------------------------------------------------
594 # Convert Bezier to Surface
596 class ConvertBezierToSurface(bpy
.types
.Operator
):
597 bl_idname
= "curvetools.convert_bezier_to_surface"
598 bl_label
= "Convert Bezier to Surface"
599 bl_description
= "Convert Bezier to Surface"
600 bl_options
= {'REGISTER', 'UNDO'}
602 Center
: BoolProperty(
605 description
="Consider center points"
608 Resolution_U
: IntProperty(
613 description
="Surface resolution U"
616 Resolution_V
: IntProperty(
621 description
="Surface resolution V"
624 def draw(self
, context
):
628 col
= layout
.column()
629 col
.prop(self
, 'Center')
630 col
.prop(self
, 'Resolution_U')
631 col
.prop(self
, 'Resolution_V')
634 def poll(cls
, context
):
635 return util
.Selected1OrMoreCurves()
637 def execute(self
, context
):
639 bpy
.ops
.object.mode_set(mode
= 'OBJECT')
640 active_object
= context
.active_object
641 curvedata
= active_object
.data
643 surfacedata
= bpy
.data
.curves
.new('Surface', type='SURFACE')
644 surfaceobject
= object_utils
.object_data_add(context
, surfacedata
)
645 surfaceobject
.matrix_world
= active_object
.matrix_world
646 surfaceobject
.rotation_euler
= active_object
.rotation_euler
647 surfacedata
.dimensions
= '3D'
648 surfaceobject
.show_wire
= True
649 surfaceobject
.show_in_front
= True
651 for spline
in curvedata
.splines
:
652 SurfaceFromBezier(surfacedata
, spline
.bezier_points
, self
.Center
)
654 for spline
in surfacedata
.splines
:
655 len_p
= len(spline
.points
)
656 len_devide_4
= round(len_p
/ 4) + 1
657 len_devide_2
= round(len_p
/ 2)
658 bpy
.ops
.object.mode_set(mode
= 'EDIT')
659 for point_index
in range(len_devide_4
, len_p
- len_devide_4
):
660 if point_index
!= len_devide_2
and point_index
!= len_devide_2
- 1:
661 spline
.points
[point_index
].select
= True
663 surfacedata
.resolution_u
= self
.Resolution_U
664 surfacedata
.resolution_v
= self
.Resolution_V
668 # ------------------------------------------------------------
671 class BezierPointsFillet(bpy
.types
.Operator
):
672 bl_idname
= "curvetools.bezier_points_fillet"
673 bl_label
= "Bezier points Fillet"
674 bl_description
= "Bezier points Fillet"
675 bl_options
= {'REGISTER', 'UNDO', 'PRESET'}
677 Fillet_radius
: FloatProperty(
683 Types
= [('Round', "Round", "Round"),
684 ('Chamfer', "Chamfer", "Chamfer")]
685 Fillet_Type
: EnumProperty(
687 description
="Fillet type",
691 def draw(self
, context
):
695 col
= layout
.column()
696 col
.prop(self
, "Fillet_radius")
697 col
.prop(self
, "Fillet_Type", expand
=True)
700 def poll(cls
, context
):
701 return util
.Selected1OrMoreCurves()
703 def execute(self
, context
):
705 if bpy
.ops
.object.mode_set
.poll():
706 bpy
.ops
.object.mode_set(mode
='EDIT')
708 splines
= bpy
.context
.object.data
.splines
709 bpy
.ops
.curve
.spline_type_set(type='BEZIER')
711 bpy
.ops
.curve
.handle_type_set(type='VECTOR')
713 for spline
in splines
:
716 for p
in spline
.bezier_points
:
717 if p
.select_control_point
:
725 for spline
in splines
:
727 bezier_points
= spline
.bezier_points
728 n
= len(bezier_points
)
734 bpy
.ops
.curve
.select_all(action
='DESELECT')
736 if j
!= 0 and j
!= n
- 1:
737 bezier_points
[j
].select_control_point
= True
738 bezier_points
[j
+ 1].select_control_point
= True
739 bpy
.ops
.curve
.subdivide()
740 selected4
= [bezier_points
[j
- 1], bezier_points
[j
],
741 bezier_points
[j
+ 1], bezier_points
[j
+ 2]]
746 bezier_points
[j
].select_control_point
= True
747 bezier_points
[j
+ 1].select_control_point
= True
748 bpy
.ops
.curve
.subdivide()
749 selected4
= [bezier_points
[n
], bezier_points
[0],
750 bezier_points
[1], bezier_points
[2]]
755 bezier_points
[j
].select_control_point
= True
756 bezier_points
[j
- 1].select_control_point
= True
757 bpy
.ops
.curve
.subdivide()
758 selected4
= [bezier_points
[0], bezier_points
[n
],
759 bezier_points
[n
- 1], bezier_points
[n
- 2]]
761 selected4
[2].co
= selected4
[1].co
762 s1
= Vector(selected4
[0].co
) - Vector(selected4
[1].co
)
763 s2
= Vector(selected4
[3].co
) - Vector(selected4
[2].co
)
765 s11
= Vector(selected4
[1].co
) + s1
* self
.Fillet_radius
766 selected4
[1].co
= s11
768 s22
= Vector(selected4
[2].co
) + s2
* self
.Fillet_radius
769 selected4
[2].co
= s22
771 if self
.Fillet_Type
== 'Round':
773 selected4
[2].handle_right_type
= 'VECTOR'
774 selected4
[1].handle_left_type
= 'VECTOR'
775 selected4
[1].handle_right_type
= 'ALIGNED'
776 selected4
[2].handle_left_type
= 'ALIGNED'
778 selected4
[1].handle_right_type
= 'VECTOR'
779 selected4
[2].handle_left_type
= 'VECTOR'
780 selected4
[2].handle_right_type
= 'ALIGNED'
781 selected4
[1].handle_left_type
= 'ALIGNED'
782 if self
.Fillet_Type
== 'Chamfer':
783 selected4
[2].handle_right_type
= 'VECTOR'
784 selected4
[1].handle_left_type
= 'VECTOR'
785 selected4
[1].handle_right_type
= 'VECTOR'
786 selected4
[2].handle_left_type
= 'VECTOR'
791 # ------------------------------------------------------------
792 # BezierDivide Operator
794 class BezierDivide(bpy
.types
.Operator
):
795 bl_idname
= "curvetools.bezier_spline_divide"
796 bl_label
= "Bezier Spline Divide"
797 bl_description
= "Bezier Divide (enters edit mode) for Fillet Curves"
798 bl_options
= {'REGISTER', 'UNDO'}
800 # align_matrix for the invoke
801 align_matrix
: Matrix()
803 Bezier_t
: FloatProperty(
804 name
="t (0% - 100%)",
806 min=0.0, soft_min
=0.0,
807 max=100.0, soft_max
=100.0,
808 description
="t (0% - 100%)"
812 def poll(cls
, context
):
813 return util
.Selected1OrMoreCurves()
815 def execute(self
, context
):
817 if bpy
.ops
.object.mode_set
.poll():
818 bpy
.ops
.object.mode_set(mode
='EDIT')
820 splines
= bpy
.context
.object.data
.splines
822 for spline
in splines
:
823 bpy
.ops
.curve
.spline_type_set(type='BEZIER')
827 for p
in spline
.bezier_points
:
828 if p
.select_control_point
:
836 for spline
in splines
:
838 bezier_points
= spline
.bezier_points
839 n
= len(bezier_points
)
844 bpy
.ops
.curve
.select_all(action
='DESELECT')
846 if (j
in ii
) and (j
+ 1 in ii
):
847 bezier_points
[j
+ jn
].select_control_point
= True
848 bezier_points
[j
+ 1 + jn
].select_control_point
= True
849 h
= mathematics
.subdivide_cubic_bezier(
850 bezier_points
[j
+ jn
].co
, bezier_points
[j
+ jn
].handle_right
,
851 bezier_points
[j
+ 1 + jn
].handle_left
, bezier_points
[j
+ 1 + jn
].co
, self
.Bezier_t
/ 100
853 bpy
.ops
.curve
.subdivide(1)
854 bezier_points
[j
+ jn
].handle_right_type
= 'FREE'
855 bezier_points
[j
+ jn
].handle_right
= h
[0]
856 bezier_points
[j
+ 1 + jn
].co
= h
[2]
857 bezier_points
[j
+ 1 + jn
].handle_left_type
= 'FREE'
858 bezier_points
[j
+ 1 + jn
].handle_left
= h
[1]
859 bezier_points
[j
+ 1 + jn
].handle_right_type
= 'FREE'
860 bezier_points
[j
+ 1 + jn
].handle_right
= h
[3]
861 bezier_points
[j
+ 2 + jn
].handle_left_type
= 'FREE'
862 bezier_points
[j
+ 2 + jn
].handle_left
= h
[4]
865 if j
== n
- 1 and (0 in ii
) and spline
.use_cyclic_u
:
866 bezier_points
[j
+ jn
].select_control_point
= True
867 bezier_points
[0].select_control_point
= True
868 h
= mathematics
.subdivide_cubic_bezier(
869 bezier_points
[j
+ jn
].co
, bezier_points
[j
+ jn
].handle_right
,
870 bezier_points
[0].handle_left
, bezier_points
[0].co
, self
.Bezier_t
/ 100
872 bpy
.ops
.curve
.subdivide(1)
873 bezier_points
[j
+ jn
].handle_right_type
= 'FREE'
874 bezier_points
[j
+ jn
].handle_right
= h
[0]
875 bezier_points
[j
+ 1 + jn
].co
= h
[2]
876 bezier_points
[j
+ 1 + jn
].handle_left_type
= 'FREE'
877 bezier_points
[j
+ 1 + jn
].handle_left
= h
[1]
878 bezier_points
[j
+ 1 + jn
].handle_right_type
= 'FREE'
879 bezier_points
[j
+ 1 + jn
].handle_right
= h
[3]
880 bezier_points
[0].handle_left_type
= 'FREE'
881 bezier_points
[0].handle_left
= h
[4]
887 # ------------------------------------------------------------
888 # CurveScaleReset Operator
890 class CurveScaleReset(bpy
.types
.Operator
):
891 bl_idname
= "curvetools.scale_reset"
892 bl_label
= "Curve Scale Reset"
893 bl_description
= "Curve Scale Reset"
894 bl_options
= {'REGISTER', 'UNDO'}
897 def poll(cls
, context
):
898 return (context
.object is not None and
899 context
.object.type == 'CURVE')
901 def execute(self
, context
):
903 current_mode
= bpy
.context
.object.mode
905 bpy
.ops
.object.mode_set(mode
= 'OBJECT')
907 oldCurve
= context
.active_object
908 oldCurveName
= oldCurve
.name
910 bpy
.ops
.object.duplicate_move(OBJECT_OT_duplicate
=None, TRANSFORM_OT_translate
=None)
911 newCurve
= context
.active_object
912 newCurve
.data
.splines
.clear()
913 newCurve
.scale
= (1.0, 1.0, 1.0)
915 oldCurve
.select_set(True)
916 newCurve
.select_set(True)
917 bpy
.context
.view_layer
.objects
.active
= newCurve
918 bpy
.ops
.object.join()
920 joinCurve
= context
.active_object
921 joinCurve
.name
= oldCurveName
923 bpy
.ops
.object.mode_set (mode
= current_mode
)
927 # ------------------------------------------------------------
930 class Split(bpy
.types
.Operator
):
931 bl_idname
= "curvetools.split"
933 bl_options
= {'REGISTER', 'UNDO'}
936 def poll(cls
, context
):
937 return util
.Selected1OrMoreCurves()
939 def execute(self
, context
):
940 selected_Curves
= util
.GetSelectedCurves()
942 for curve
in selected_Curves
:
945 bezier_spline_points
= []
946 select_bezier_points
= {}
949 for spline
in curve
.data
.splines
:
950 if spline
.type == 'BEZIER':
952 select_bezier_points
[i_bp
] = [len(spline
.bezier_points
)]
953 for i
in range(len(spline
.bezier_points
)):
954 bezier_point
= spline
.bezier_points
[i
]
955 points
[i
]=[bezier_point
.co
[:], bezier_point
.handle_left
[:], bezier_point
.handle_right
[:]]
957 if spline
.bezier_points
[i
].select_control_point
:
958 select_bezier_points
[i_bp
].append(i
)
960 bezier_spline_points
.append(points
)
963 select_points
[i_p
] = [len(spline
.points
)]
964 for i
in range(len(spline
.points
)):
965 point
= spline
.points
[i
]
966 points
[i
]=[point
.co
[:], spline
.type]
967 if spline
.points
[i
].select
:
968 select_points
[i_p
].append(i
)
970 spline_points
.append(points
)
972 curve
.data
.splines
.clear()
974 for key
in select_bezier_points
:
978 if select_bezier_points
[key
][-1] == select_bezier_points
[key
][0]-1:
979 select_bezier_points
[key
].pop()
981 for i
in select_bezier_points
[key
][1:]+[select_bezier_points
[key
][0]-1]:
983 spline
= curve
.data
.splines
.new('BEZIER')
984 spline
.bezier_points
.add(i
-num
)
986 for j
in range(num
, i
):
987 bezier_point
= spline
.bezier_points
[j
-num
]
989 bezier_point
.co
= bezier_spline_points
[key
][j
][0]
990 bezier_point
.handle_left
= bezier_spline_points
[key
][j
][1]
991 bezier_point
.handle_right
= bezier_spline_points
[key
][j
][2]
992 bezier_point
= spline
.bezier_points
[-1]
993 bezier_point
.co
= bezier_spline_points
[key
][i
][0]
994 bezier_point
.handle_left
= bezier_spline_points
[key
][i
][1]
995 bezier_point
.handle_right
= bezier_spline_points
[key
][i
][2]
998 for key
in select_points
:
1002 if select_points
[key
][-1] == select_points
[key
][0]-1:
1003 select_points
[key
].pop()
1005 for i
in select_points
[key
][1:]+[select_points
[key
][0]-1]:
1007 spline
= curve
.data
.splines
.new(spline_points
[key
][i
][1])
1008 spline
.points
.add(i
-num
)
1010 for j
in range(num
, i
):
1011 point
= spline
.points
[j
-num
]
1013 point
.co
= spline_points
[key
][j
][0]
1014 point
= spline
.points
[-1]
1015 point
.co
= spline_points
[key
][i
][0]
1020 class SeparateOutline(bpy
.types
.Operator
):
1021 bl_idname
= "curvetools.sep_outline"
1022 bl_label
= "Separate Outline"
1023 bl_options
= {'REGISTER', 'UNDO'}
1024 bl_description
= "Makes 'Outline' separate mesh"
1027 def poll(cls
, context
):
1028 return util
.Selected1OrMoreCurves()
1030 def execute(self
, context
):
1031 bpy
.ops
.object.mode_set(mode
= 'EDIT')
1032 bpy
.ops
.curve
.separate()
1036 class CurveBoolean(bpy
.types
.Operator
):
1037 bl_idname
= "curvetools.bezier_curve_boolean"
1038 bl_description
= "Curve Boolean"
1039 bl_label
= "Curve Boolean"
1040 bl_options
= {'REGISTER', 'UNDO'}
1042 operation
: bpy
.props
.EnumProperty(name
='Type', items
=[
1043 ('UNION', 'Union', 'Boolean OR', 0),
1044 ('INTERSECTION', 'Intersection', 'Boolean AND', 1),
1045 ('DIFFERENCE', 'Difference', 'Active minus Selected', 2),
1047 number
: IntProperty(
1048 name
="Spline Number",
1051 description
="Spline Number"
1055 def poll(cls
, context
):
1056 return util
.Selected1OrMoreCurves()
1058 def draw(self
, context
):
1059 layout
= self
.layout
1062 col
= layout
.column()
1063 col
.prop(self
, "operation")
1064 if self
.operation
== 'DIFFERENCE':
1065 col
.prop(self
, "number")
1067 def execute(self
, context
):
1068 current_mode
= bpy
.context
.object.mode
1070 if bpy
.ops
.object.mode_set
.poll():
1071 bpy
.ops
.object.mode_set(mode
= 'OBJECT')
1073 selected_Curves
= util
.GetSelectedCurves()
1074 len_selected_curves
= len(selected_Curves
)
1075 if len_selected_curves
< 2:
1081 for iCurve
in range(0, len_selected_curves
):
1082 len_splines
= len(selected_Curves
[iCurve
].data
.splines
)
1083 max_number
+= len_splines
1085 if self
.number
< min_number
:
1086 self
.number
= min_number
1087 if self
.number
> max_number
:
1088 self
.number
= max_number
1093 for iCurve
in range(0, len_selected_curves
):
1094 len_splines
= len(selected_Curves
[iCurve
].data
.splines
)
1095 for iSpline
in range(0, len_splines
):
1096 if j
== self
.number
:
1097 first_curve
= iCurve
1098 first_spline
= iSpline
1101 bpy
.ops
.object.select_all(action
='DESELECT')
1103 spline1
= selected_Curves
[first_curve
].data
.splines
[first_spline
]
1104 matrix_world1
= selected_Curves
[first_curve
].matrix_world
1106 len_spline1
= len(spline1
.bezier_points
)
1108 dataCurve
= bpy
.data
.curves
.new(self
.operation
, type='CURVE')
1109 dataCurve
.dimensions
= '2D'
1110 newSpline1
= dataCurve
.splines
.new(type='BEZIER')
1111 newSpline1
.use_cyclic_u
= True
1112 newSpline1
.bezier_points
.add(len_spline1
- 1)
1113 for n
in range(0, len_spline1
):
1114 newSpline1
.bezier_points
[n
].co
= matrix_world1
@ spline1
.bezier_points
[n
].co
1115 newSpline1
.bezier_points
[n
].handle_left_type
= spline1
.bezier_points
[n
].handle_left_type
1116 newSpline1
.bezier_points
[n
].handle_left
= matrix_world1
@ spline1
.bezier_points
[n
].handle_left
1117 newSpline1
.bezier_points
[n
].handle_right_type
= spline1
.bezier_points
[n
].handle_right_type
1118 newSpline1
.bezier_points
[n
].handle_right
= matrix_world1
@ spline1
.bezier_points
[n
].handle_right
1120 Curve
= object_utils
.object_data_add(context
, dataCurve
)
1121 bpy
.context
.view_layer
.objects
.active
= Curve
1122 Curve
.select_set(True)
1123 Curve
.location
= (0.0, 0.0, 0.0)
1126 for iCurve
in range(0, len_selected_curves
):
1127 matrix_world
= selected_Curves
[iCurve
].matrix_world
1128 len_splines
= len(selected_Curves
[iCurve
].data
.splines
)
1129 for iSpline
in range(0, len_splines
):
1130 if iCurve
== first_curve
and iSpline
== first_spline
:
1132 spline
= selected_Curves
[iCurve
].data
.splines
[iSpline
]
1133 len_spline
= len(spline
.bezier_points
)
1134 newSpline
= dataCurve
.splines
.new(type='BEZIER')
1135 newSpline
.use_cyclic_u
= True
1136 newSpline
.bezier_points
.add(len_spline
- 1)
1137 for n
in range(0, len_spline
):
1138 newSpline
.bezier_points
[n
].co
= matrix_world
@ spline
.bezier_points
[n
].co
1139 newSpline
.bezier_points
[n
].handle_left_type
= spline
.bezier_points
[n
].handle_left_type
1140 newSpline
.bezier_points
[n
].handle_left
= matrix_world
@ spline
.bezier_points
[n
].handle_left
1141 newSpline
.bezier_points
[n
].handle_right_type
= spline
.bezier_points
[n
].handle_right_type
1142 newSpline
.bezier_points
[n
].handle_right
= matrix_world
@ spline
.bezier_points
[n
].handle_right
1144 bpy
.ops
.object.mode_set(mode
= 'EDIT')
1145 bpy
.ops
.curve
.select_all(action
='SELECT')
1146 splines
= internal
.getSelectedSplines(True, True)
1147 if len(splines
) < 2:
1149 splineA
= splines
[0]
1150 splineB
= splines
[1]
1151 dataCurve
.splines
.active
= newSpline1
1153 if not internal
.bezierBooleanGeometry(splineA
, splineB
, self
.operation
):
1154 self
.report({'WARNING'}, 'Invalid selection.')
1155 return {'CANCELLED'}
1159 bpy
.ops
.object.mode_set(mode
= 'EDIT')
1160 bpy
.ops
.curve
.select_all(action
='SELECT')
1164 # ----------------------------
1165 # Set first points operator
1166 class SetFirstPoints(bpy
.types
.Operator
):
1167 bl_idname
= "curvetools.set_first_points"
1168 bl_label
= "Set first points"
1169 bl_description
= "Set the selected points as the first point of each spline"
1170 bl_options
= {'REGISTER', 'UNDO'}
1173 def poll(cls
, context
):
1174 return util
.Selected1OrMoreCurves()
1176 def execute(self
, context
):
1177 splines_to_invert
= []
1179 curve
= bpy
.context
.object
1181 bpy
.ops
.object.mode_set('INVOKE_REGION_WIN', mode
='EDIT')
1183 # Check non-cyclic splines to invert
1184 for i
in range(len(curve
.data
.splines
)):
1185 b_points
= curve
.data
.splines
[i
].bezier_points
1187 if i
not in self
.cyclic_splines
: # Only for non-cyclic splines
1188 if b_points
[len(b_points
) - 1].select_control_point
:
1189 splines_to_invert
.append(i
)
1191 # Reorder points of cyclic splines, and set all handles to "Automatic"
1193 # Check first selected point
1194 cyclic_splines_new_first_pt
= {}
1195 for i
in self
.cyclic_splines
:
1196 sp
= curve
.data
.splines
[i
]
1198 for t
in range(len(sp
.bezier_points
)):
1199 bp
= sp
.bezier_points
[t
]
1200 if bp
.select_control_point
or bp
.select_right_handle
or bp
.select_left_handle
:
1201 cyclic_splines_new_first_pt
[i
] = t
1202 break # To take only one if there are more
1205 for spline_idx
in cyclic_splines_new_first_pt
:
1206 sp
= curve
.data
.splines
[spline_idx
]
1208 spline_old_coords
= []
1209 for bp_old
in sp
.bezier_points
:
1210 coords
= (bp_old
.co
[0], bp_old
.co
[1], bp_old
.co
[2])
1212 left_handle_type
= str(bp_old
.handle_left_type
)
1213 left_handle_length
= float(bp_old
.handle_left
.length
)
1215 float(bp_old
.handle_left
.x
),
1216 float(bp_old
.handle_left
.y
),
1217 float(bp_old
.handle_left
.z
)
1219 right_handle_type
= str(bp_old
.handle_right_type
)
1220 right_handle_length
= float(bp_old
.handle_right
.length
)
1221 right_handle_xyz
= (
1222 float(bp_old
.handle_right
.x
),
1223 float(bp_old
.handle_right
.y
),
1224 float(bp_old
.handle_right
.z
)
1226 spline_old_coords
.append(
1227 [coords
, left_handle_type
,
1228 right_handle_type
, left_handle_length
,
1229 right_handle_length
, left_handle_xyz
,
1233 for t
in range(len(sp
.bezier_points
)):
1234 bp
= sp
.bezier_points
1236 if t
+ cyclic_splines_new_first_pt
[spline_idx
] + 1 <= len(bp
) - 1:
1237 new_index
= t
+ cyclic_splines_new_first_pt
[spline_idx
] + 1
1239 new_index
= t
+ cyclic_splines_new_first_pt
[spline_idx
] + 1 - len(bp
)
1241 bp
[t
].co
= Vector(spline_old_coords
[new_index
][0])
1243 bp
[t
].handle_left
.length
= spline_old_coords
[new_index
][3]
1244 bp
[t
].handle_right
.length
= spline_old_coords
[new_index
][4]
1246 bp
[t
].handle_left_type
= "FREE"
1247 bp
[t
].handle_right_type
= "FREE"
1249 bp
[t
].handle_left
.x
= spline_old_coords
[new_index
][5][0]
1250 bp
[t
].handle_left
.y
= spline_old_coords
[new_index
][5][1]
1251 bp
[t
].handle_left
.z
= spline_old_coords
[new_index
][5][2]
1253 bp
[t
].handle_right
.x
= spline_old_coords
[new_index
][6][0]
1254 bp
[t
].handle_right
.y
= spline_old_coords
[new_index
][6][1]
1255 bp
[t
].handle_right
.z
= spline_old_coords
[new_index
][6][2]
1257 bp
[t
].handle_left_type
= spline_old_coords
[new_index
][1]
1258 bp
[t
].handle_right_type
= spline_old_coords
[new_index
][2]
1260 # Invert the non-cyclic splines designated above
1261 for i
in range(len(splines_to_invert
)):
1262 bpy
.ops
.curve
.select_all('INVOKE_REGION_WIN', action
='DESELECT')
1264 bpy
.ops
.object.editmode_toggle('INVOKE_REGION_WIN')
1265 curve
.data
.splines
[splines_to_invert
[i
]].bezier_points
[0].select_control_point
= True
1266 bpy
.ops
.object.editmode_toggle('INVOKE_REGION_WIN')
1268 bpy
.ops
.curve
.switch_direction()
1270 bpy
.ops
.curve
.select_all('INVOKE_REGION_WIN', action
='DESELECT')
1272 # Keep selected the first vert of each spline
1273 bpy
.ops
.object.editmode_toggle('INVOKE_REGION_WIN')
1274 for i
in range(len(curve
.data
.splines
)):
1275 if not curve
.data
.splines
[i
].use_cyclic_u
:
1276 bp
= curve
.data
.splines
[i
].bezier_points
[0]
1278 bp
= curve
.data
.splines
[i
].bezier_points
[
1279 len(curve
.data
.splines
[i
].bezier_points
) - 1
1282 bp
.select_control_point
= True
1283 bp
.select_right_handle
= True
1284 bp
.select_left_handle
= True
1286 bpy
.ops
.object.editmode_toggle('INVOKE_REGION_WIN')
1290 def invoke(self
, context
, event
):
1291 curve
= bpy
.context
.object
1293 # Check if all curves are Bezier, and detect which ones are cyclic
1294 self
.cyclic_splines
= []
1295 for i
in range(len(curve
.data
.splines
)):
1296 if curve
.data
.splines
[i
].type != "BEZIER":
1297 self
.report({'WARNING'}, "All splines must be Bezier type")
1299 return {'CANCELLED'}
1301 if curve
.data
.splines
[i
].use_cyclic_u
:
1302 self
.cyclic_splines
.append(i
)
1304 self
.execute(context
)
1305 self
.report({'INFO'}, "First points have been set")
1311 bpy
.utils
.register_class(operators
)
1315 bpy
.utils
.unregister_class(operators
)
1317 if __name__
== "__main__":
1322 OperatorCurveLength
,
1323 OperatorSplinesInfo
,
1324 OperatorSegmentsInfo
,
1325 OperatorOriginToSpline0Start
,
1326 OperatorIntersectCurves
,
1328 OperatorSweepCurves
,
1330 OperatorSplinesSetResolution
,
1331 OperatorSplinesRemoveZeroSegment
,
1332 OperatorSplinesRemoveShort
,
1333 OperatorSplinesJoinNeighbouring
,
1334 ConvertSelectedFacesToBezier
,
1335 ConvertBezierToSurface
,