Use URL icon, add Tip: prefix, increase lower margin
[blender-addons-contrib.git] / curve_tools / CurveIntersections.py
1 from . import Math
2 from . import Curves
3 from . import Util
4
5 from mathutils import *
6
7 import bpy
8
9
10 algoPOV = None
11 algoDIR = None
12
13
14 class BezierSegmentIntersectionPoint:
15     def __init__(self, segment, parameter, intersectionPoint):
16         self.segment = segment
17         self.parameter = parameter
18         self.intersectionPoint = intersectionPoint
19         
20         
21 class BezierSegmentsIntersector:
22     def __init__(self, segment1, segment2, worldMatrix1, worldMatrix2):
23         self.segment1 = segment1
24         self.segment2 = segment2
25         self.worldMatrix1 = worldMatrix1
26         self.worldMatrix2 = worldMatrix2
27     
28     
29     def CalcFirstIntersection(self, nrSamples1, nrSamples2):
30         algorithm = bpy.context.scene.curvetools.IntersectCurvesAlgorithm
31         
32         if algorithm == '3D': return self.CalcFirstRealIntersection3D(nrSamples1, nrSamples2)
33         
34         if algorithm == 'From View':
35             global algoDIR
36             if not algoDIR is None: return self.CalcFirstRealIntersectionFromViewDIR(nrSamples1, nrSamples2)
37             
38             global algoPOV
39             if not algoPOV is None: return self.CalcFirstRealIntersectionFromViewPOV(nrSamples1, nrSamples2)
40         
41         return None
42         
43     
44     def CalcFirstIntersection3D(self, nrSamples1, nrSamples2):
45         fltNrSamples1 = float(nrSamples1)
46         fltNrSamples2 = float(nrSamples2)
47         
48         limitDistance = bpy.context.scene.curvetools.LimitDistance
49         
50         for iSample1 in range(nrSamples1):
51             segPar10 = float(iSample1) / fltNrSamples1
52             segPar11 = float(iSample1 + 1) / fltNrSamples1
53             P0 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = segPar10)
54             P1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = segPar11)
55             
56             for iSample2 in range(nrSamples2):
57                 segPar20 = float(iSample2) / fltNrSamples2
58                 segPar21 = float(iSample2 + 1) / fltNrSamples2
59                 Q0 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = segPar20)
60                 Q1 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = segPar21)
61                 
62                 intersectionPointData = Math.CalcIntersectionPointLineSegments(P0, P1, Q0, Q1, limitDistance)
63                 if intersectionPointData is None: continue
64                 
65                 intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / fltNrSamples1)
66                 intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1, intersectionSegment1Parameter, intersectionPointData[2])
67                 
68                 intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / fltNrSamples2)
69                 intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2, intersectionSegment2Parameter, intersectionPointData[3])
70                 
71                 return [intersectionPoint1, intersectionPoint2]
72                 
73         return None
74         
75     
76     def CalcFirstRealIntersection3D(self, nrSamples1, nrSamples2):
77         fltNrSamples1 = float(nrSamples1)
78         fltNrSamples2 = float(nrSamples2)
79         
80         limitDistance = bpy.context.scene.curvetools.LimitDistance
81         
82         for iSample1 in range(nrSamples1):
83             segPar10 = float(iSample1) / fltNrSamples1
84             segPar11 = float(iSample1 + 1) / fltNrSamples1
85             P0 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = segPar10)
86             P1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = segPar11)
87             
88             for iSample2 in range(nrSamples2):
89                 segPar20 = float(iSample2) / fltNrSamples2
90                 segPar21 = float(iSample2 + 1) / fltNrSamples2
91                 Q0 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = segPar20)
92                 Q1 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = segPar21)
93                 
94                 intersectionPointData = Math.CalcIntersectionPointLineSegments(P0, P1, Q0, Q1, limitDistance)
95                 if intersectionPointData is None: continue
96                 
97                 # intersection point can't be an existing point
98                 intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / (fltNrSamples1))
99                 worldPoint1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = intersectionSegment1Parameter)
100                 if (Math.IsSamePoint(P0, worldPoint1, limitDistance)) or (Math.IsSamePoint(P1, worldPoint1, limitDistance)):
101                     intersectionPoint1 = None
102                 else:
103                     intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1, intersectionSegment1Parameter, worldPoint1)
104                 
105                 intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / (fltNrSamples2))
106                 worldPoint2 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = intersectionSegment2Parameter)
107                 if (Math.IsSamePoint(Q0, worldPoint2, limitDistance)) or (Math.IsSamePoint(Q1, worldPoint2, limitDistance)):
108                     intersectionPoint2 = None
109                 else:
110                     intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2, intersectionSegment2Parameter, worldPoint2)
111                 
112                 return [intersectionPoint1, intersectionPoint2]
113                 
114         return None
115         
116     
117     def CalcFirstIntersectionFromViewDIR(self, nrSamples1, nrSamples2):
118         global algoDIR
119         
120         fltNrSamples1 = float(nrSamples1)
121         fltNrSamples2 = float(nrSamples2)
122         
123         for iSample1 in range(nrSamples1):
124             segPar10 = float(iSample1) / fltNrSamples1
125             segPar11 = float(iSample1 + 1) / fltNrSamples1
126             P0 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = segPar10)
127             P1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = segPar11)
128             
129             for iSample2 in range(nrSamples2):
130                 segPar20 = float(iSample2) / fltNrSamples2
131                 segPar21 = float(iSample2 + 1) / fltNrSamples2
132                 Q0 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = segPar20)
133                 Q1 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = segPar21)
134                 
135                 intersectionPointData = Math.CalcIntersectionPointsLineSegmentsDIR(P0, P1, Q0, Q1, algoDIR)
136                 if intersectionPointData is None: continue
137                 
138                 intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / fltNrSamples1)
139                 worldPoint1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = intersectionSegment1Parameter)
140                 intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1, intersectionSegment1Parameter, worldPoint1)
141                 
142                 intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / fltNrSamples2)
143                 worldPoint2 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = intersectionSegment2Parameter)
144                 intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2, intersectionSegment2Parameter, worldPoint2)
145                 
146                 return [intersectionPoint1, intersectionPoint2]
147                 
148         return None
149         
150     
151     def CalcFirstRealIntersectionFromViewDIR(self, nrSamples1, nrSamples2):
152         global algoDIR
153         
154         fltNrSamples1 = float(nrSamples1)
155         fltNrSamples2 = float(nrSamples2)
156         
157         limitDistance = bpy.context.scene.curvetools.LimitDistance
158         
159         for iSample1 in range(nrSamples1):
160             segPar10 = float(iSample1) / fltNrSamples1
161             segPar11 = float(iSample1 + 1) / fltNrSamples1
162             P0 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = segPar10)
163             P1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = segPar11)
164             
165             for iSample2 in range(nrSamples2):
166                 segPar20 = float(iSample2) / fltNrSamples2
167                 segPar21 = float(iSample2 + 1) / fltNrSamples2
168                 Q0 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = segPar20)
169                 Q1 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = segPar21)
170                 
171                 intersectionPointData = Math.CalcIntersectionPointsLineSegmentsDIR(P0, P1, Q0, Q1, algoDIR)
172                 if intersectionPointData is None: continue
173                 
174                 # intersection point can't be an existing point
175                 intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / (fltNrSamples1))
176                 worldPoint1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = intersectionSegment1Parameter)
177                 if (Math.IsSamePoint(P0, worldPoint1, limitDistance)) or (Math.IsSamePoint(P1, worldPoint1, limitDistance)):
178                     intersectionPoint1 = None
179                 else:
180                     intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1, intersectionSegment1Parameter, worldPoint1)
181                 
182                 intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / (fltNrSamples2))
183                 worldPoint2 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = intersectionSegment2Parameter)
184                 if (Math.IsSamePoint(Q0, worldPoint2, limitDistance)) or (Math.IsSamePoint(Q1, worldPoint2, limitDistance)):
185                     intersectionPoint2 = None
186                 else:
187                     intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2, intersectionSegment2Parameter, worldPoint2)
188                 
189                 return [intersectionPoint1, intersectionPoint2]
190                 
191         return None
192         
193     
194     def CalcFirstIntersectionFromViewPOV(self, nrSamples1, nrSamples2):
195         global algoPOV
196         
197         fltNrSamples1 = float(nrSamples1)
198         fltNrSamples2 = float(nrSamples2)
199         
200         for iSample1 in range(nrSamples1):
201             segPar10 = float(iSample1) / fltNrSamples1
202             segPar11 = float(iSample1 + 1) / fltNrSamples1
203             P0 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = segPar10)
204             P1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = segPar11)
205             
206             for iSample2 in range(nrSamples2):
207                 segPar20 = float(iSample2) / fltNrSamples2
208                 segPar21 = float(iSample2 + 1) / fltNrSamples2
209                 Q0 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = segPar20)
210                 Q1 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = segPar21)
211                 
212                 intersectionPointData = Math.CalcIntersectionPointsLineSegmentsPOV(P0, P1, Q0, Q1, algoPOV)
213                 if intersectionPointData is None: continue
214                 
215                 intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / fltNrSamples1)
216                 worldPoint1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = intersectionSegment1Parameter)
217                 intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1, intersectionSegment1Parameter, worldPoint1)
218                 
219                 intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / fltNrSamples2)
220                 worldPoint2 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = intersectionSegment2Parameter)
221                 intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2, intersectionSegment2Parameter, worldPoint2)
222                 
223                 return [intersectionPoint1, intersectionPoint2]
224                 
225         return None
226         
227     
228     def CalcFirstRealIntersectionFromViewPOV(self, nrSamples1, nrSamples2):
229         global algoPOV
230         
231         fltNrSamples1 = float(nrSamples1)
232         fltNrSamples2 = float(nrSamples2)
233         
234         limitDistance = bpy.context.scene.curvetools.LimitDistance
235         
236         for iSample1 in range(nrSamples1):
237             segPar10 = float(iSample1) / fltNrSamples1
238             segPar11 = float(iSample1 + 1) / fltNrSamples1
239             P0 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = segPar10)
240             P1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = segPar11)
241             
242             for iSample2 in range(nrSamples2):
243                 segPar20 = float(iSample2) / fltNrSamples2
244                 segPar21 = float(iSample2 + 1) / fltNrSamples2
245                 Q0 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = segPar20)
246                 Q1 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = segPar21)
247                 
248                 intersectionPointData = Math.CalcIntersectionPointsLineSegmentsPOV(P0, P1, Q0, Q1, algoPOV)
249                 if intersectionPointData is None: continue
250                 
251                 # intersection point can't be an existing point
252                 intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / fltNrSamples1)
253                 worldPoint1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = intersectionSegment1Parameter)
254                 if (Math.IsSamePoint(P0, worldPoint1, limitDistance)) or (Math.IsSamePoint(P1, worldPoint1, limitDistance)):
255                     intersectionPoint1 = None
256                 else:
257                     intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1, intersectionSegment1Parameter, worldPoint1)
258                 
259                 intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / fltNrSamples2)
260                 worldPoint2 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = intersectionSegment2Parameter)
261                 if (Math.IsSamePoint(Q0, worldPoint2, limitDistance)) or (Math.IsSamePoint(Q1, worldPoint2, limitDistance)):
262                     intersectionPoint2 = None
263                 else:
264                     intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2, intersectionSegment2Parameter, worldPoint2)
265                 
266                 return [intersectionPoint1, intersectionPoint2]
267                 
268         return None
269     
270     
271     
272     
273     def CalcIntersections(self, nrSamples1, nrSamples2):
274         algorithm = bpy.context.scene.curvetools.IntersectCurvesAlgorithm
275         
276         if algorithm == '3D': return self.CalcIntersections3D(nrSamples1, nrSamples2)
277         
278         if algorithm == 'From View':
279             global algoDIR
280             if not algoDIR is None: return self.CalcIntersectionsFromViewDIR(nrSamples1, nrSamples2)
281             
282             global algoPOV
283             if not algoPOV is None: return self.CalcIntersectionsFromViewPOV(nrSamples1, nrSamples2)
284         
285         return [[], []]
286         
287     
288     def CalcIntersections3D(self, nrSamples1, nrSamples2):
289         rvIntersections1 = []
290         rvIntersections2 = []
291         
292         fltNrSamples1 = float(nrSamples1)
293         fltNrSamples2 = float(nrSamples2)
294         
295         limitDistance = bpy.context.scene.curvetools.LimitDistance
296         
297         
298         for iSample1 in range(nrSamples1):
299             segPar10 = float(iSample1) / fltNrSamples1
300             segPar11 = float(iSample1 + 1) / fltNrSamples1
301             P0 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = segPar10)
302             P1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = segPar11)
303             
304             for iSample2 in range(nrSamples2):
305                 segPar20 = float(iSample2) / fltNrSamples2
306                 segPar21 = float(iSample2 + 1) / fltNrSamples2
307                 Q0 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = segPar20)
308                 Q1 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = segPar21)
309                 
310                 intersectionPointData = Math.CalcIntersectionPointLineSegments(P0, P1, Q0, Q1, limitDistance)
311                 if intersectionPointData is None: continue
312                 
313                 intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / fltNrSamples1)
314                 worldPoint1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = intersectionSegment1Parameter)
315                 intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1, intersectionSegment1Parameter, worldPoint1)
316                 rvIntersections1.append(intersectionPoint1)
317                 
318                 intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / fltNrSamples2)
319                 worldPoint2 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = intersectionSegment2Parameter)
320                 intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2, intersectionSegment2Parameter, worldPoint2)
321                 rvIntersections2.append(intersectionPoint2)
322                 
323         return [rvIntersections1, rvIntersections2]
324         
325     
326     def CalcIntersectionsFromViewDIR(self, nrSamples1, nrSamples2):
327         global algoDIR
328         
329         rvIntersections1 = []
330         rvIntersections2 = []
331         
332         fltNrSamples1 = float(nrSamples1)
333         fltNrSamples2 = float(nrSamples2)
334         
335         for iSample1 in range(nrSamples1):
336             segPar10 = float(iSample1) / fltNrSamples1
337             segPar11 = float(iSample1 + 1) / fltNrSamples1
338             P0 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = segPar10)
339             P1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = segPar11)
340             
341             for iSample2 in range(nrSamples2):
342                 segPar20 = float(iSample2) / fltNrSamples2
343                 segPar21 = float(iSample2 + 1) / fltNrSamples2
344                 Q0 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = segPar20)
345                 Q1 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = segPar21)
346                 
347                 intersectionPointData = Math.CalcIntersectionPointsLineSegmentsDIR(P0, P1, Q0, Q1, algoDIR)
348                 if intersectionPointData is None: continue
349                 
350                 intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / fltNrSamples1)
351                 worldPoint1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = intersectionSegment1Parameter)
352                 intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1, intersectionSegment1Parameter, worldPoint1)
353                 rvIntersections1.append(intersectionPoint1)
354                 
355                 intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / fltNrSamples2)
356                 worldPoint2 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = intersectionSegment2Parameter)
357                 intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2, intersectionSegment2Parameter, worldPoint2)
358                 rvIntersections2.append(intersectionPoint2)
359                 
360         return [rvIntersections1, rvIntersections2]
361         
362     
363     def CalcIntersectionsFromViewPOV(self, nrSamples1, nrSamples2):
364         global algoPOV
365         
366         rvIntersections1 = []
367         rvIntersections2 = []
368         
369         fltNrSamples1 = float(nrSamples1)
370         fltNrSamples2 = float(nrSamples2)
371         
372         for iSample1 in range(nrSamples1):
373             segPar10 = float(iSample1) / fltNrSamples1
374             segPar11 = float(iSample1 + 1) / fltNrSamples1
375             P0 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = segPar10)
376             P1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = segPar11)
377             
378             for iSample2 in range(nrSamples2):
379                 segPar20 = float(iSample2) / fltNrSamples2
380                 segPar21 = float(iSample2 + 1) / fltNrSamples2
381                 Q0 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = segPar20)
382                 Q1 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = segPar21)
383                 
384                 intersectionPointData = Math.CalcIntersectionPointsLineSegmentsPOV(P0, P1, Q0, Q1, algoPOV)
385                 if intersectionPointData is None: continue
386                 
387                 intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / fltNrSamples1)
388                 worldPoint1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter = intersectionSegment1Parameter)
389                 intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1, intersectionSegment1Parameter, worldPoint1)
390                 rvIntersections1.append(intersectionPoint1)
391                 
392                 intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / fltNrSamples2)
393                 worldPoint2 = self.worldMatrix2 * self.segment2.CalcPoint(parameter = intersectionSegment2Parameter)
394                 intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2, intersectionSegment2Parameter, worldPoint2)
395                 rvIntersections2.append(intersectionPoint2)
396                 
397         return [rvIntersections1, rvIntersections2]
398
399
400 class BezierSplineIntersectionPoint:
401     def __init__(self, spline, bezierSegmentIntersectionPoint):
402         self.spline = spline
403         self.bezierSegmentIntersectionPoint = bezierSegmentIntersectionPoint
404         
405         
406 class BezierSplinesIntersector:
407     def __init__(self, spline1, spline2, worldMatrix1, worldMatrix2):
408         self.spline1 = spline1
409         self.spline2 = spline2
410         self.worldMatrix1 = worldMatrix1
411         self.worldMatrix2 = worldMatrix2
412         
413         
414     def CalcIntersections(self):
415         rvIntersections1 = []
416         rvIntersections2 = []
417         
418         try: nrSamplesPerSegment1 = int(self.spline1.resolution / self.spline1.nrSegments)
419         except: nrSamplesPerSegment1 = 2
420         if nrSamplesPerSegment1 < 2: nrSamplesPerSegment1 = 2
421         
422         try: nrSamplesPerSegment2 = int(self.spline2.resolution / self.spline2.nrSegments)
423         except: nrSamplesPerSegment2 = 2
424         if nrSamplesPerSegment2 < 2: nrSamplesPerSegment2 = 2
425         
426         for segment1 in self.spline1.segments:
427             for segment2 in self.spline2.segments:
428                 segmentsIntersector = BezierSegmentsIntersector(segment1, segment2, self.worldMatrix1, self.worldMatrix2)
429                 segmentIntersections = segmentsIntersector.CalcIntersections(nrSamplesPerSegment1, nrSamplesPerSegment2)
430                 if segmentIntersections is None: continue
431                 
432                 segment1Intersections = segmentIntersections[0]
433                 for segmentIntersection in segment1Intersections: 
434                     splineIntersection = BezierSplineIntersectionPoint(self.spline1, segmentIntersection)
435                     rvIntersections1.append(splineIntersection)
436                 
437                 segment2Intersections = segmentIntersections[1]
438                 for segmentIntersection in segment2Intersections: 
439                     splineIntersection = BezierSplineIntersectionPoint(self.spline2, segmentIntersection)
440                     rvIntersections2.append(splineIntersection)
441         
442         return [rvIntersections1, rvIntersections2]
443         
444         
445 class CurvesIntersector:
446     @staticmethod
447     def FromSelection():
448         selObjects = bpy.context.selected_objects
449         if len(selObjects) != 2: raise Exception("len(selObjects) != 2") # shouldn't be possible
450         
451         blenderActiveCurve = bpy.context.active_object
452         blenderOtherCurve = selObjects[0]
453         if blenderActiveCurve == blenderOtherCurve: blenderOtherCurve = selObjects[1]
454         
455         aCurve = Curves.Curve(blenderActiveCurve)
456         oCurve = Curves.Curve(blenderOtherCurve)
457         
458         return CurvesIntersector(aCurve, oCurve)
459     
460
461     @staticmethod
462     def ResetGlobals():
463         global algoPOV
464         algoPOV = None
465         global algoDIR
466         algoDIR = None
467     
468
469     @staticmethod
470     def InitGlobals():
471         CurvesIntersector.ResetGlobals()
472         
473         
474         algo = bpy.context.scene.curvetools.IntersectCurvesAlgorithm
475         if algo == 'From View':
476             regionView3D = Util.GetFirstRegionView3D()
477             if regionView3D is None: 
478                 print("### ERROR: regionView3D is None. Stopping.")
479                 return
480                 
481             viewPerspective = regionView3D.view_perspective
482             print("--", "viewPerspective:", viewPerspective)
483             
484             
485             if viewPerspective == 'ORTHO':
486                 viewMatrix = regionView3D.view_matrix
487                 print("--", "viewMatrix:")
488                 print(viewMatrix)
489                 
490                 global algoDIR
491                 algoDIR = Vector((viewMatrix[2][0], viewMatrix[2][1], viewMatrix[2][2]))
492                 print("--", "algoDIR:", algoDIR)
493
494             # ## TODO: doesn't work properly
495             if viewPerspective == 'PERSP':
496                 viewMatrix = regionView3D.view_matrix
497                 print("--", "viewMatrix:")
498                 print(viewMatrix)
499                 
500                 global algoPOV
501                 algoPOV = regionView3D.view_location.copy()
502                 print("--", "algoPOV:", algoPOV)
503                 
504                 otherPOV = Vector((viewMatrix[0][3], viewMatrix[1][3], viewMatrix[2][3]))
505                 print("--", "otherPOV:", otherPOV)
506                 
507                 localPOV = Vector((0, 0, 0))
508                 globalPOV = viewMatrix * localPOV
509                 print("--", "globalPOV:", globalPOV)
510
511                 
512                 perspMatrix = regionView3D.perspective_matrix
513                 print("--", "perspMatrix:")
514                 print(perspMatrix)
515                 
516                 globalPOVPersp = perspMatrix * localPOV
517                 print("--", "globalPOVPersp:", globalPOVPersp)
518                 
519             if viewPerspective == 'CAMERA':
520                 camera = bpy.context.scene.camera
521                 if camera is None: 
522                     print("### ERROR: camera is None. Stopping.")
523                     return
524                     
525                 print("--", "camera:", camera)
526                 cameraData = camera.data
527                 print("--", "cameraData.type:", cameraData.type)
528                 
529                 cameraMatrix = camera.matrix_world
530                 print("--", "cameraMatrix:")
531                 print(cameraMatrix)
532
533                 if cameraData.type == 'ORTHO':
534                     cameraMatrix = camera.matrix_world
535                 
536                     global algoDIR
537                     #algoDIR = Vector((cameraMatrix[2][0], cameraMatrix[2][1], cameraMatrix[2][2]))
538                     algoDIR = Vector((- cameraMatrix[0][2], - cameraMatrix[1][2], - cameraMatrix[2][2]))
539                     print("--", "algoDIR:", algoDIR)
540
541                 if cameraData.type == 'PERSP':
542                     global algoPOV
543                     algoPOV = camera.location.copy()
544                     print("--", "algoPOV:", algoPOV)
545
546         
547     def __init__(self, activeCurve, otherCurve):
548         self.activeCurve = activeCurve
549         self.otherCurve = otherCurve
550         
551         CurvesIntersector.InitGlobals()
552
553         
554     def CalcIntersections(self):
555         rvIntersections1 = []
556         rvIntersections2 = []
557         
558         worldMatrix1 = self.activeCurve.curve.matrix_world
559         worldMatrix2 = self.otherCurve.curve.matrix_world
560         
561         for spline1 in self.activeCurve.splines:
562             for spline2 in self.otherCurve.splines:
563                 splineIntersector = BezierSplinesIntersector(spline1, spline2, worldMatrix1, worldMatrix2)
564                 splineIntersections = splineIntersector.CalcIntersections()
565                 if splineIntersections is None: continue
566                 
567                 spline1Intersections = splineIntersections[0]
568                 for splineIntersection in spline1Intersections: rvIntersections1.append(splineIntersection)
569                 
570                 spline2Intersections = splineIntersections[1]
571                 for splineIntersection in spline2Intersections: rvIntersections2.append(splineIntersection)
572         
573         return [rvIntersections1, rvIntersections2]
574         
575         
576     def CalcAndApplyIntersections(self):
577         mode = bpy.context.scene.curvetools.IntersectCurvesMode
578         
579         if mode == 'Empty': return self.CalcAndApplyEmptyAtIntersections()
580         if mode == 'Insert': return self.CalcAndApplyInsertAtIntersections()
581         if mode == 'Split': return self.CalcAndApplySplitAtIntersections()
582         
583         return [0, 0]
584         
585         
586     def CalcAndApplyEmptyAtIntersections(self):
587         intersections = self.CalcIntersections()
588         intersectionsActive = intersections[0]
589         intersectionsOther = intersections[1]
590         
591         nrActive = 0
592         nrOther = 0
593         
594         affect = bpy.context.scene.curvetools.IntersectCurvesAffect
595         
596         if (affect == 'Both') or (affect == 'Active'):
597             for splineIntersection in intersectionsActive:
598                 iPoint = splineIntersection.bezierSegmentIntersectionPoint.intersectionPoint
599                 bpy.ops.object.empty_add(type='PLAIN_AXES', view_align=False, location=(iPoint.x, iPoint.y, iPoint.z), rotation=(0, 0, 0))
600                 nrActive += 1
601         
602         if (affect == 'Both') or (affect == 'Other'):
603             for splineIntersection in intersectionsOther:
604                 iPoint = splineIntersection.bezierSegmentIntersectionPoint.intersectionPoint
605                 bpy.ops.object.empty_add(type='PLAIN_AXES', view_align=False, location=(iPoint.x, iPoint.y, iPoint.z), rotation=(0, 0, 0))
606                 nrOther += 1
607         
608         return [nrActive, nrOther]
609         
610         
611     def CalcAndApplyInsertAtIntersections(self):
612         nrActive = 0
613         nrOther = 0
614         
615         affect = bpy.context.scene.curvetools.IntersectCurvesAffect
616         affectA = (affect == 'Both') or (affect == 'Active')
617         affectO = (affect == 'Both') or (affect == 'Other')
618         
619         
620         for iSplineA in range(len(self.activeCurve.splines)):
621             splineA = self.activeCurve.splines[iSplineA]
622             nrSegmentsA = len(splineA.segments)
623             resPerSegA = splineA.resolutionPerSegment
624         
625             for iSplineO in range(len(self.otherCurve.splines)):
626                 splineO = self.otherCurve.splines[iSplineO]
627                 nrSegmentsO = len(splineO.segments)
628                 resPerSegO = splineO.resolutionPerSegment
629                 
630                 
631                 iSegA = 0
632                 while True:
633                     segA = splineA.segments[iSegA]
634                     
635                     iSegO = 0
636                     while True:
637                         segO = splineO.segments[iSegO]
638                         
639                         segIntersector = BezierSegmentsIntersector(segA, segO, self.activeCurve.worldMatrix, self.otherCurve.worldMatrix)
640                         segFirstIntersection = segIntersector.CalcFirstIntersection(resPerSegA, resPerSegO)
641                         
642                         if not segFirstIntersection is None:
643                             intPointA = segFirstIntersection[0]
644                             intPointO = segFirstIntersection[1]
645                             if (not intPointA is None) and (not intPointO is None):    # else does something weird if 1 of them is None.. 
646                                 if affectA:
647                                     if not intPointA is None:
648                                         splineA.InsertPoint(segA, intPointA.parameter)
649                                         
650                                         nrActive += 1
651                                         nrSegmentsA += 1
652                                         
653                                 if affectO:
654                                     if not intPointO is None:
655                                         splineO.InsertPoint(segO, intPointO.parameter)
656                                         
657                                         nrOther += 1
658                                         nrSegmentsO += 1
659    
660    
661                         iSegO += 1
662                         if not (iSegO < nrSegmentsO): break
663                             
664                     iSegA += 1
665                     if not (iSegA < nrSegmentsA): break
666             
667             
668                 if affectO: splineO.RefreshInScene()
669             
670             if affectA: splineA.RefreshInScene()
671         
672         
673         return [nrActive, nrOther]
674         
675         
676     def CalcAndApplySplitAtIntersections(self):
677         nrActive = 0
678         nrOther = 0
679         
680         affect = bpy.context.scene.curvetools.IntersectCurvesAffect
681         affectA = (affect == 'Both') or (affect == 'Active')
682         affectO = (affect == 'Both') or (affect == 'Other')
683         
684         nrSplinesA = len(self.activeCurve.splines)
685         nrSplinesO = len(self.otherCurve.splines)
686         
687         iSplineA = 0
688         while True:
689             splineA = self.activeCurve.splines[iSplineA]
690             nrSegmentsA = len(splineA.segments)
691             resPerSegA = splineA.resolutionPerSegment
692         
693             iSplineO = 0
694             while True:
695                 splineO = self.otherCurve.splines[iSplineO]
696                 nrSegmentsO = len(splineO.segments)
697                 resPerSegO = splineO.resolutionPerSegment
698                 
699                 
700                 iSegA = 0
701                 while True:
702                     segA = splineA.segments[iSegA]
703                     
704                     iSegO = 0
705                     while True:
706                         segO = splineO.segments[iSegO]
707                         
708                         segIntersector = BezierSegmentsIntersector(segA, segO, self.activeCurve.worldMatrix, self.otherCurve.worldMatrix)
709                         segFirstIntersection = segIntersector.CalcFirstIntersection(resPerSegA, resPerSegO)
710                         
711                         if not segFirstIntersection is None:
712                             intPointA = segFirstIntersection[0]
713                             intPointO = segFirstIntersection[1]
714                             if (not intPointA is None) and (not intPointO is None):    # else does something weird if 1 of them is None.. 
715                                 if affectA:
716                                     if not intPointA is None:
717                                         print("--", "splineA.Split():")
718                                         newSplinesA = splineA.Split(segA, intPointA.parameter)
719                                         if not newSplinesA is None:
720                                             newResolutions = splineA.CalcDivideResolution(segA, intPointA.parameter)
721                                             newSplinesA[0].resolution = newResolutions[0]
722                                             newSplinesA[1].resolution = newResolutions[1]
723                                                                                     
724                                             splineA = newSplinesA[0]
725                                             self.activeCurve.splines[iSplineA] = splineA
726                                             self.activeCurve.splines.insert(iSplineA + 1, newSplinesA[1])
727                                         
728                                             nrActive += 1
729                                             
730                                 if affectO:
731                                     if not intPointO is None:
732                                         print("--", "splineO.Split():")
733                                         newSplinesO = splineO.Split(segO, intPointO.parameter)
734                                         if not newSplinesO is None:
735                                             newResolutions = splineO.CalcDivideResolution(segO, intPointO.parameter)
736                                             newSplinesO[0].resolution = newResolutions[0]
737                                             newSplinesO[1].resolution = newResolutions[1]
738                                         
739                                             splineO = newSplinesO[0]
740                                             self.otherCurve.splines[iSplineO] = splineO
741                                             self.otherCurve.splines.insert(iSplineO + 1, newSplinesO[1])
742                                             
743                                             nrOther += 1
744
745                                             
746                         nrSegmentsO = len(splineO.segments)
747                         iSegO += 1
748                         if not (iSegO < nrSegmentsO): break
749                         
750                     nrSegmentsA = len(splineA.segments)       
751                     iSegA += 1
752                     if not (iSegA < nrSegmentsA): break
753             
754                 nrSplinesO = len(self.otherCurve.splines)
755                 iSplineO += 1
756                 if not (iSplineO < nrSplinesO): break
757             
758             nrSplinesA = len(self.activeCurve.splines)
759             iSplineA += 1
760             if not (iSplineA < nrSplinesA): break
761         
762         if affectA:
763             print("")
764             print("--", "self.activeCurve.RebuildInScene():")
765             self.activeCurve.RebuildInScene()
766         if affectO: 
767             print("")
768             print("--", "self.otherCurve.RebuildInScene():")
769             self.otherCurve.RebuildInScene()
770         
771         return [nrActive, nrOther]
772         
773         
774         
775         
776         
777         
778         
779         
780         
781         
782         
783         
784         
785         
786         
787         
788         
789         
790