Update for API change: scene.cursor_location -> scene.cursor.location
[blender-addons-contrib.git] / curve_tools / Operators.py
1 import time
2 import threading
3
4 import bpy
5 from bpy.props import *
6
7 from . import Properties
8 from . import Curves
9 from . import CurveIntersections
10 from . import Util
11 from . import Surfaces
12
13
14
15 class OperatorSelectionInfo(bpy.types.Operator):
16     bl_idname = "curvetools2.operatorselectioninfo"
17     bl_label = "Selection Info"
18     bl_description = "Maintains a list of selected objects in the order they were selected"
19
20
21     @classmethod
22     def poll(cls, context):
23         selectedObjectNames = Properties.CurveTools2SelectedObject.GetSelectedObjectNames()
24         selectedBlenderObjectNames = Properties.CurveTools2SelectedObject.GetSelectedBlenderObjectNames()
25
26         sleepTime = 0.02
27
28         lock = threading.Lock()
29         lock_holder = threading.Thread(target = Properties.CurveTools2SelectedObject.UpdateThreadTarget, args=(lock, sleepTime, selectedObjectNames, selectedBlenderObjectNames), name='OperatorSelectionInfoThread')
30         # lock_holder = threading.Thread(target = Properties.CurveTools2SelectedObject.UpdateThreadTarget2, args=(lock, sleepTime, selectedObjectNames, selectedBlenderObjectNames, context), name='OperatorSelectionInfoThread')
31         lock_holder.setDaemon(True)
32         lock_holder.start()
33
34         return True
35
36
37     def execute(self, context):
38         nrSelectedObjects = bpy.context.scene.curvetools.NrSelectedObjects
39
40         self.report({'INFO'}, "Selection Info: nrSelectedObjects: %d" % nrSelectedObjects)
41
42         selectedObjects = bpy.context.scene.curvetools.SelectedObjects
43         selectedObjectValues = selectedObjects.values()
44         for i, selectedObject in enumerate(selectedObjectValues):
45             print("--", "selected object %d of %d: %s" % (i + 1, nrSelectedObjects, selectedObject.name))
46
47         return {'FINISHED'}
48
49
50
51 # 1 CURVE SELECTED
52 # ################
53 class OperatorCurveInfo(bpy.types.Operator):
54     bl_idname = "curvetools2.operatorcurveinfo"
55     bl_label = "Info"
56     bl_description = "Displays general info about the active/selected curve"
57
58
59     @classmethod
60     def poll(cls, context):
61         return Util.Selected1Curve()
62
63
64     def execute(self, context):
65         curve = Curves.Curve(context.active_object)
66
67         nrSplines = len(curve.splines)
68         nrSegments = 0
69         nrEmptySplines = 0
70         for spline in curve.splines:
71             nrSegments += spline.nrSegments
72             if spline.nrSegments < 1: nrEmptySplines += 1
73
74
75         self.report({'INFO'}, "nrSplines: %d; nrSegments: %d; nrEmptySplines: %d" % (nrSplines, nrSegments, nrEmptySplines))
76
77         return {'FINISHED'}
78
79
80
81 class OperatorCurveLength(bpy.types.Operator):
82     bl_idname = "curvetools2.operatorcurvelength"
83     bl_label = "Length"
84     bl_description = "Calculates the length of the active/selected curve"
85
86
87     @classmethod
88     def poll(cls, context):
89         return Util.Selected1Curve()
90
91
92     def execute(self, context):
93         curve = Curves.Curve(context.active_object)
94
95         context.scene.curvetools.CurveLength = curve.length
96
97         return {'FINISHED'}
98
99
100
101 class OperatorSplinesInfo(bpy.types.Operator):
102     bl_idname = "curvetools2.operatorsplinesinfo"
103     bl_label = "Info"
104     bl_description = "Displays general info about the splines of the active/selected curve"
105
106
107     @classmethod
108     def poll(cls, context):
109         return Util.Selected1Curve()
110
111
112     def execute(self, context):
113         curve = Curves.Curve(context.active_object)
114         nrSplines = len(curve.splines)
115
116         print("")
117         print("OperatorSplinesInfo:", "nrSplines:", nrSplines)
118
119         nrEmptySplines = 0
120         for iSpline, spline in enumerate(curve.splines):
121             print("--", "spline %d of %d: nrSegments: %d" % (iSpline + 1, nrSplines, spline.nrSegments))
122
123             if spline.nrSegments < 1:
124                 nrEmptySplines += 1
125                 print("--", "--", "## WARNING: spline has no segments and will therefor be ignored in any further calculations")
126
127
128         self.report({'INFO'}, "nrSplines: %d; nrEmptySplines: %d" % (nrSplines, nrEmptySplines) + " -- more info: see console")
129
130         return {'FINISHED'}
131
132
133
134 class OperatorSegmentsInfo(bpy.types.Operator):
135     bl_idname = "curvetools2.operatorsegmentsinfo"
136     bl_label = "Info"
137     bl_description = "Displays general info about the segments of the active/selected curve"
138
139
140     @classmethod
141     def poll(cls, context):
142         return Util.Selected1Curve()
143
144
145     def execute(self, context):
146         curve = Curves.Curve(context.active_object)
147         nrSplines = len(curve.splines)
148         nrSegments = 0
149
150         print("")
151         print("OperatorSegmentsInfo:", "nrSplines:", nrSplines)
152
153         nrEmptySplines = 0
154         for iSpline, spline in enumerate(curve.splines):
155             nrSegmentsSpline = spline.nrSegments
156             print("--", "spline %d of %d: nrSegments: %d" % (iSpline + 1, nrSplines, nrSegmentsSpline))
157
158             if nrSegmentsSpline < 1:
159                 nrEmptySplines += 1
160                 print("--", "--", "## WARNING: spline has no segments and will therefor be ignored in any further calculations")
161                 continue
162
163             for iSegment, segment in enumerate(spline.segments):
164                 print("--", "--", "segment %d of %d coefficients:" % (iSegment + 1, nrSegmentsSpline))
165                 print("--", "--", "--", "C0: %.6f, %.6f, %.6f" % (segment.coeff0.x, segment.coeff0.y, segment.coeff0.z))
166
167             nrSegments += nrSegmentsSpline
168
169         self.report({'INFO'}, "nrSplines: %d; nrSegments: %d; nrEmptySplines: %d" % (nrSplines, nrSegments, nrEmptySplines))
170
171         return {'FINISHED'}
172
173
174
175 class OperatorOriginToSpline0Start(bpy.types.Operator):
176     bl_idname = "curvetools2.operatororigintospline0start"
177     bl_label = "OriginToSpline0Start"
178     bl_description = "Sets the origin of the active/selected curve to the starting point of the (first) spline. Nice for curve modifiers."
179
180
181     @classmethod
182     def poll(cls, context):
183         return Util.Selected1Curve()
184
185
186     def execute(self, context):
187         blCurve = context.active_object
188         blSpline = blCurve.data.splines[0]
189         newOrigin = blCurve.matrix_world * blSpline.bezier_points[0].co
190
191         origOrigin = bpy.context.scene.cursor.location.copy()
192         print("--", "origOrigin: %.6f, %.6f, %.6f" % (origOrigin.x, origOrigin.y, origOrigin.z))
193         print("--", "newOrigin: %.6f, %.6f, %.6f" % (newOrigin.x, newOrigin.y, newOrigin.z))
194
195         bpy.context.scene.cursor.location = newOrigin
196         bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
197         bpy.context.scene.cursor.location = origOrigin
198
199         self.report({'INFO'}, "TODO: OperatorOriginToSpline0Start")
200
201         return {'FINISHED'}
202
203
204
205 # 2 CURVES SELECTED
206 # #################
207 class OperatorIntersectCurves(bpy.types.Operator):
208     bl_idname = "curvetools2.operatorintersectcurves"
209     bl_label = "Intersect"
210     bl_description = "Intersects selected curves"
211
212
213     @classmethod
214     def poll(cls, context):
215         return Util.Selected2Curves()
216
217
218     def execute(self, context):
219         print("### TODO: OperatorIntersectCurves.execute()")
220
221         algo = context.scene.curvetools.IntersectCurvesAlgorithm
222         print("-- algo:", algo)
223
224
225         mode = context.scene.curvetools.IntersectCurvesMode
226         print("-- mode:", mode)
227         # if mode == 'Split':
228             # self.report({'WARNING'}, "'Split' mode is not implemented yet -- <<STOPPING>>")
229             # return {'CANCELLED'}
230
231         affect = context.scene.curvetools.IntersectCurvesAffect
232         print("-- affect:", affect)
233
234
235         curveIntersector = CurveIntersections.CurvesIntersector.FromSelection()
236         rvIntersectionNrs = curveIntersector.CalcAndApplyIntersections()
237
238         self.report({'INFO'}, "Active curve points: %d; other curve points: %d" % (rvIntersectionNrs[0], rvIntersectionNrs[1]))
239
240         return {'FINISHED'}
241
242
243
244 class OperatorLoftCurves(bpy.types.Operator):
245     bl_idname = "curvetools2.operatorloftcurves"
246     bl_label = "Loft"
247     bl_description = "Lofts selected curves"
248
249
250     @classmethod
251     def poll(cls, context):
252         return Util.Selected2Curves()
253
254
255     def execute(self, context):
256         #print("### TODO: OperatorLoftCurves.execute()")
257
258         loftedSurface = Surfaces.LoftedSurface.FromSelection()
259         loftedSurface.AddToScene()
260
261         self.report({'INFO'}, "OperatorLoftCurves.execute()")
262
263         return {'FINISHED'}
264
265
266
267 class OperatorSweepCurves(bpy.types.Operator):
268     bl_idname = "curvetools2.operatorsweepcurves"
269     bl_label = "Sweep"
270     bl_description = "Sweeps the active curve along to other curve (rail)"
271
272
273     @classmethod
274     def poll(cls, context):
275         return Util.Selected2Curves()
276
277
278     def execute(self, context):
279         #print("### TODO: OperatorSweepCurves.execute()")
280
281         sweptSurface = Surfaces.SweptSurface.FromSelection()
282         sweptSurface.AddToScene()
283
284         self.report({'INFO'}, "OperatorSweepCurves.execute()")
285
286         return {'FINISHED'}
287
288
289
290 # 3 CURVES SELECTED
291 # #################
292 class OperatorBirail(bpy.types.Operator):
293     bl_idname = "curvetools2.operatorbirail"
294     bl_label = "Birail"
295     bl_description = "Generates a birailed surface from 3 selected curves -- in order: rail1, rail2 and profile"
296
297
298     @classmethod
299     def poll(cls, context):
300         return Util.Selected3Curves()
301
302
303     def execute(self, context):
304         birailedSurface = Surfaces.BirailedSurface.FromSelection()
305         birailedSurface.AddToScene()
306
307         self.report({'INFO'}, "OperatorBirail.execute()")
308
309         return {'FINISHED'}
310
311
312
313 # 1 OR MORE CURVES SELECTED
314 # #########################
315 class OperatorSplinesSetResolution(bpy.types.Operator):
316     bl_idname = "curvetools2.operatorsplinessetresolution"
317     bl_label = "SplinesSetResolution"
318     bl_description = "Sets the resolution of all splines"
319
320
321     @classmethod
322     def poll(cls, context):
323         return Util.Selected1OrMoreCurves()
324
325
326     def execute(self, context):
327         splRes = context.scene.curvetools.SplineResolution
328         selCurves = Util.GetSelectedCurves()
329
330         for blCurve in selCurves:
331             for spline in blCurve.data.splines:
332                 spline.resolution_u = splRes
333
334         return {'FINISHED'}
335
336
337
338 class OperatorSplinesRemoveZeroSegment(bpy.types.Operator):
339     bl_idname = "curvetools2.operatorsplinesremovezerosegment"
340     bl_label = "SplinesRemoveZeroSegment"
341     bl_description = "Removes splines with no segments -- they seem to creep up, sometimes.."
342
343
344     @classmethod
345     def poll(cls, context):
346         return Util.Selected1OrMoreCurves()
347
348
349     def execute(self, context):
350         selCurves = Util.GetSelectedCurves()
351
352         for blCurve in selCurves:
353             curve = Curves.Curve(blCurve)
354             nrSplines = curve.nrSplines
355
356             splinesToRemove = []
357             for spline in curve.splines:
358                 if len(spline.segments) < 1: splinesToRemove.append(spline)
359             nrRemovedSplines = len(splinesToRemove)
360
361             for spline in splinesToRemove: curve.splines.remove(spline)
362
363             if nrRemovedSplines > 0: curve.RebuildInScene()
364
365             self.report({'INFO'}, "Removed %d of %d splines" % (nrRemovedSplines, nrSplines))
366
367         return {'FINISHED'}
368
369
370
371 class OperatorSplinesRemoveShort(bpy.types.Operator):
372     bl_idname = "curvetools2.operatorsplinesremoveshort"
373     bl_label = "SplinesRemoveShort"
374     bl_description = "Removes splines with a length smaller than the threshold"
375
376
377     @classmethod
378     def poll(cls, context):
379         return Util.Selected1OrMoreCurves()
380
381
382     def execute(self, context):
383         threshold = context.scene.curvetools.SplineRemoveLength
384         selCurves = Util.GetSelectedCurves()
385
386         for blCurve in selCurves:
387             curve = Curves.Curve(blCurve)
388             nrSplines = curve.nrSplines
389
390             nrRemovedSplines = curve.RemoveShortSplines(threshold)
391             if nrRemovedSplines > 0: curve.RebuildInScene()
392
393             self.report({'INFO'}, "Removed %d of %d splines" % (nrRemovedSplines, nrSplines))
394
395         return {'FINISHED'}
396
397
398
399 class OperatorSplinesJoinNeighbouring(bpy.types.Operator):
400     bl_idname = "curvetools2.operatorsplinesjoinneighbouring"
401     bl_label = "SplinesJoinNeighbouring"
402     bl_description = "Joins neighbouring splines within a distance smaller than the threshold"
403
404
405     @classmethod
406     def poll(cls, context):
407         return Util.Selected1OrMoreCurves()
408
409
410     def execute(self, context):
411         selCurves = Util.GetSelectedCurves()
412
413         for blCurve in selCurves:
414             curve = Curves.Curve(blCurve)
415             nrSplines = curve.nrSplines
416
417             threshold = context.scene.curvetools.SplineJoinDistance
418             startEnd = context.scene.curvetools.SplineJoinStartEnd
419             mode = context.scene.curvetools.SplineJoinMode
420
421             nrJoins = curve.JoinNeighbouringSplines(startEnd, threshold, mode)
422             if nrJoins > 0: curve.RebuildInScene()
423
424             self.report({'INFO'}, "Applied %d joins on %d splines; resulting nrSplines: %d" % (nrJoins, nrSplines, curve.nrSplines))
425
426         return {'FINISHED'}