1 # SPDX-License-Identifier: GPL-2.0-or-later
4 from . import mathematics
8 from mathutils
import Vector
14 class BezierSegmentIntersectionPoint
:
15 def __init__(self
, segment
, parameter
, intersectionPoint
):
16 self
.segment
= segment
17 self
.parameter
= parameter
18 self
.intersectionPoint
= intersectionPoint
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
28 def CalcFirstIntersection(self
, nrSamples1
, nrSamples2
):
29 algorithm
= bpy
.context
.scene
.curvetools
.IntersectCurvesAlgorithm
32 return self
.CalcFirstRealIntersection3D(nrSamples1
, nrSamples2
)
34 if algorithm
== 'From_View':
36 if algoDIR
is not None:
37 return self
.CalcFirstRealIntersectionFromViewDIR(nrSamples1
, nrSamples2
)
40 if algoPOV
is not None:
41 return self
.CalcFirstRealIntersectionFromViewPOV(nrSamples1
, nrSamples2
)
45 def CalcFirstIntersection3D(self
, nrSamples1
, nrSamples2
):
46 fltNrSamples1
= float(nrSamples1
)
47 fltNrSamples2
= float(nrSamples2
)
49 limitDistance
= bpy
.context
.scene
.curvetools
.LimitDistance
51 for iSample1
in range(nrSamples1
):
52 segPar10
= float(iSample1
) / fltNrSamples1
53 segPar11
= float(iSample1
+ 1) / fltNrSamples1
54 P0
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar10
)
55 P1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar11
)
57 for iSample2
in range(nrSamples2
):
58 segPar20
= float(iSample2
) / fltNrSamples2
59 segPar21
= float(iSample2
+ 1) / fltNrSamples2
60 Q0
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar20
)
61 Q1
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar21
)
63 intersectionPointData
= mathematics
.CalcIntersectionPointLineSegments(P0
, P1
, Q0
, Q1
, limitDistance
)
64 if intersectionPointData
is None:
67 intersectionSegment1Parameter
= segPar10
+ (intersectionPointData
[0] / fltNrSamples1
)
68 intersectionPoint1
= BezierSegmentIntersectionPoint(self
.segment1
,
69 intersectionSegment1Parameter
,
70 intersectionPointData
[2])
72 intersectionSegment2Parameter
= segPar20
+ (intersectionPointData
[1] / fltNrSamples2
)
73 intersectionPoint2
= BezierSegmentIntersectionPoint(self
.segment2
,
74 intersectionSegment2Parameter
,
75 intersectionPointData
[3])
77 return [intersectionPoint1
, intersectionPoint2
]
81 def CalcFirstRealIntersection3D(self
, nrSamples1
, nrSamples2
):
82 fltNrSamples1
= float(nrSamples1
)
83 fltNrSamples2
= float(nrSamples2
)
85 limitDistance
= bpy
.context
.scene
.curvetools
.LimitDistance
87 for iSample1
in range(nrSamples1
):
88 segPar10
= float(iSample1
) / fltNrSamples1
89 segPar11
= float(iSample1
+ 1) / fltNrSamples1
90 P0
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar10
)
91 P1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar11
)
93 for iSample2
in range(nrSamples2
):
94 segPar20
= float(iSample2
) / fltNrSamples2
95 segPar21
= float(iSample2
+ 1) / fltNrSamples2
96 Q0
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar20
)
97 Q1
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar21
)
99 intersectionPointData
= mathematics
.CalcIntersectionPointLineSegments(P0
, P1
, Q0
, Q1
, limitDistance
)
100 if intersectionPointData
is None:
103 # intersection point can't be an existing point
104 intersectionSegment1Parameter
= segPar10
+ (intersectionPointData
[0] / (fltNrSamples1
))
105 worldPoint1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=intersectionSegment1Parameter
)
106 if (mathematics
.IsSamePoint(P0
, worldPoint1
, limitDistance
)) or \
107 (mathematics
.IsSamePoint(P1
, worldPoint1
, limitDistance
)):
109 intersectionPoint1
= None
111 intersectionPoint1
= BezierSegmentIntersectionPoint(self
.segment1
,
112 intersectionSegment1Parameter
,
115 intersectionSegment2Parameter
= segPar20
+ (intersectionPointData
[1] / (fltNrSamples2
))
116 worldPoint2
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=intersectionSegment2Parameter
)
117 if (mathematics
.IsSamePoint(Q0
, worldPoint2
, limitDistance
)) or \
118 (mathematics
.IsSamePoint(Q1
, worldPoint2
, limitDistance
)):
120 intersectionPoint2
= None
122 intersectionPoint2
= BezierSegmentIntersectionPoint(self
.segment2
,
123 intersectionSegment2Parameter
,
126 return [intersectionPoint1
, intersectionPoint2
]
130 def CalcFirstIntersectionFromViewDIR(self
, nrSamples1
, nrSamples2
):
133 fltNrSamples1
= float(nrSamples1
)
134 fltNrSamples2
= float(nrSamples2
)
136 for iSample1
in range(nrSamples1
):
137 segPar10
= float(iSample1
) / fltNrSamples1
138 segPar11
= float(iSample1
+ 1) / fltNrSamples1
139 P0
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar10
)
140 P1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar11
)
142 for iSample2
in range(nrSamples2
):
143 segPar20
= float(iSample2
) / fltNrSamples2
144 segPar21
= float(iSample2
+ 1) / fltNrSamples2
145 Q0
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar20
)
146 Q1
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar21
)
148 intersectionPointData
= mathematics
.CalcIntersectionPointsLineSegmentsDIR(P0
, P1
, Q0
, Q1
, algoDIR
)
149 if intersectionPointData
is None:
152 intersectionSegment1Parameter
= segPar10
+ (intersectionPointData
[0] / fltNrSamples1
)
153 worldPoint1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=intersectionSegment1Parameter
)
154 intersectionPoint1
= BezierSegmentIntersectionPoint(self
.segment1
,
155 intersectionSegment1Parameter
,
158 intersectionSegment2Parameter
= segPar20
+ (intersectionPointData
[1] / fltNrSamples2
)
159 worldPoint2
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=intersectionSegment2Parameter
)
160 intersectionPoint2
= BezierSegmentIntersectionPoint(self
.segment2
,
161 intersectionSegment2Parameter
,
164 return [intersectionPoint1
, intersectionPoint2
]
168 def CalcFirstRealIntersectionFromViewDIR(self
, nrSamples1
, nrSamples2
):
171 fltNrSamples1
= float(nrSamples1
)
172 fltNrSamples2
= float(nrSamples2
)
174 limitDistance
= bpy
.context
.scene
.curvetools
.LimitDistance
176 for iSample1
in range(nrSamples1
):
177 segPar10
= float(iSample1
) / fltNrSamples1
178 segPar11
= float(iSample1
+ 1) / fltNrSamples1
179 P0
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar10
)
180 P1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar11
)
182 for iSample2
in range(nrSamples2
):
183 segPar20
= float(iSample2
) / fltNrSamples2
184 segPar21
= float(iSample2
+ 1) / fltNrSamples2
185 Q0
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar20
)
186 Q1
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar21
)
188 intersectionPointData
= mathematics
.CalcIntersectionPointsLineSegmentsDIR(P0
, P1
, Q0
, Q1
, algoDIR
)
189 if intersectionPointData
is None:
192 # intersection point can't be an existing point
193 intersectionSegment1Parameter
= segPar10
+ (intersectionPointData
[0] / (fltNrSamples1
))
194 worldPoint1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=intersectionSegment1Parameter
)
195 if (mathematics
.IsSamePoint(P0
, worldPoint1
, limitDistance
)) or \
196 (mathematics
.IsSamePoint(P1
, worldPoint1
, limitDistance
)):
198 intersectionPoint1
= None
200 intersectionPoint1
= BezierSegmentIntersectionPoint(self
.segment1
,
201 intersectionSegment1Parameter
,
204 intersectionSegment2Parameter
= segPar20
+ (intersectionPointData
[1] / (fltNrSamples2
))
205 worldPoint2
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=intersectionSegment2Parameter
)
206 if (mathematics
.IsSamePoint(Q0
, worldPoint2
, limitDistance
)) or \
207 (mathematics
.IsSamePoint(Q1
, worldPoint2
, limitDistance
)):
209 intersectionPoint2
= None
211 intersectionPoint2
= BezierSegmentIntersectionPoint(self
.segment2
,
212 intersectionSegment2Parameter
,
215 return [intersectionPoint1
, intersectionPoint2
]
219 def CalcFirstIntersectionFromViewPOV(self
, nrSamples1
, nrSamples2
):
222 fltNrSamples1
= float(nrSamples1
)
223 fltNrSamples2
= float(nrSamples2
)
225 for iSample1
in range(nrSamples1
):
226 segPar10
= float(iSample1
) / fltNrSamples1
227 segPar11
= float(iSample1
+ 1) / fltNrSamples1
228 P0
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar10
)
229 P1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar11
)
231 for iSample2
in range(nrSamples2
):
232 segPar20
= float(iSample2
) / fltNrSamples2
233 segPar21
= float(iSample2
+ 1) / fltNrSamples2
234 Q0
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar20
)
235 Q1
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar21
)
237 intersectionPointData
= mathematics
.CalcIntersectionPointsLineSegmentsPOV(P0
, P1
, Q0
, Q1
, algoPOV
)
238 if intersectionPointData
is None:
241 intersectionSegment1Parameter
= segPar10
+ (intersectionPointData
[0] / fltNrSamples1
)
242 worldPoint1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=intersectionSegment1Parameter
)
243 intersectionPoint1
= BezierSegmentIntersectionPoint(self
.segment1
,
244 intersectionSegment1Parameter
,
247 intersectionSegment2Parameter
= segPar20
+ (intersectionPointData
[1] / fltNrSamples2
)
248 worldPoint2
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=intersectionSegment2Parameter
)
249 intersectionPoint2
= BezierSegmentIntersectionPoint(self
.segment2
,
250 intersectionSegment2Parameter
,
253 return [intersectionPoint1
, intersectionPoint2
]
257 def CalcFirstRealIntersectionFromViewPOV(self
, nrSamples1
, nrSamples2
):
260 fltNrSamples1
= float(nrSamples1
)
261 fltNrSamples2
= float(nrSamples2
)
263 limitDistance
= bpy
.context
.scene
.curvetools
.LimitDistance
265 for iSample1
in range(nrSamples1
):
266 segPar10
= float(iSample1
) / fltNrSamples1
267 segPar11
= float(iSample1
+ 1) / fltNrSamples1
268 P0
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar10
)
269 P1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar11
)
271 for iSample2
in range(nrSamples2
):
272 segPar20
= float(iSample2
) / fltNrSamples2
273 segPar21
= float(iSample2
+ 1) / fltNrSamples2
274 Q0
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar20
)
275 Q1
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar21
)
277 intersectionPointData
= mathematics
.CalcIntersectionPointsLineSegmentsPOV(P0
, P1
, Q0
, Q1
, algoPOV
)
278 if intersectionPointData
is None:
281 # intersection point can't be an existing point
282 intersectionSegment1Parameter
= segPar10
+ (intersectionPointData
[0] / fltNrSamples1
)
283 worldPoint1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=intersectionSegment1Parameter
)
284 if (mathematics
.IsSamePoint(P0
, worldPoint1
, limitDistance
)) or \
285 (mathematics
.IsSamePoint(P1
, worldPoint1
, limitDistance
)):
287 intersectionPoint1
= None
289 intersectionPoint1
= BezierSegmentIntersectionPoint(self
.segment1
,
290 intersectionSegment1Parameter
,
293 intersectionSegment2Parameter
= segPar20
+ (intersectionPointData
[1] / fltNrSamples2
)
294 worldPoint2
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=intersectionSegment2Parameter
)
295 if (mathematics
.IsSamePoint(Q0
, worldPoint2
, limitDistance
)) or \
296 (mathematics
.IsSamePoint(Q1
, worldPoint2
, limitDistance
)):
298 intersectionPoint2
= None
300 intersectionPoint2
= BezierSegmentIntersectionPoint(self
.segment2
,
301 intersectionSegment2Parameter
,
304 return [intersectionPoint1
, intersectionPoint2
]
308 def CalcIntersections(self
, nrSamples1
, nrSamples2
):
309 algorithm
= bpy
.context
.scene
.curvetools
.IntersectCurvesAlgorithm
311 if algorithm
== '3D':
312 return self
.CalcIntersections3D(nrSamples1
, nrSamples2
)
314 if algorithm
== 'From_View':
316 if algoDIR
is not None:
317 return self
.CalcIntersectionsFromViewDIR(nrSamples1
, nrSamples2
)
320 if algoPOV
is not None:
321 return self
.CalcIntersectionsFromViewPOV(nrSamples1
, nrSamples2
)
325 def CalcIntersections3D(self
, nrSamples1
, nrSamples2
):
326 rvIntersections1
= []
327 rvIntersections2
= []
329 fltNrSamples1
= float(nrSamples1
)
330 fltNrSamples2
= float(nrSamples2
)
332 limitDistance
= bpy
.context
.scene
.curvetools
.LimitDistance
334 for iSample1
in range(nrSamples1
):
335 segPar10
= float(iSample1
) / fltNrSamples1
336 segPar11
= float(iSample1
+ 1) / fltNrSamples1
337 P0
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar10
)
338 P1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar11
)
340 for iSample2
in range(nrSamples2
):
341 segPar20
= float(iSample2
) / fltNrSamples2
342 segPar21
= float(iSample2
+ 1) / fltNrSamples2
343 Q0
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar20
)
344 Q1
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar21
)
346 intersectionPointData
= mathematics
.CalcIntersectionPointLineSegments(P0
, P1
, Q0
, Q1
, limitDistance
)
347 if intersectionPointData
is None:
350 intersectionSegment1Parameter
= segPar10
+ (intersectionPointData
[0] / fltNrSamples1
)
351 worldPoint1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=intersectionSegment1Parameter
)
352 intersectionPoint1
= BezierSegmentIntersectionPoint(self
.segment1
,
353 intersectionSegment1Parameter
,
355 rvIntersections1
.append(intersectionPoint1
)
357 intersectionSegment2Parameter
= segPar20
+ (intersectionPointData
[1] / fltNrSamples2
)
358 worldPoint2
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=intersectionSegment2Parameter
)
359 intersectionPoint2
= BezierSegmentIntersectionPoint(self
.segment2
,
360 intersectionSegment2Parameter
,
362 rvIntersections2
.append(intersectionPoint2
)
364 return [rvIntersections1
, rvIntersections2
]
366 def CalcIntersectionsFromViewDIR(self
, nrSamples1
, nrSamples2
):
369 rvIntersections1
= []
370 rvIntersections2
= []
372 fltNrSamples1
= float(nrSamples1
)
373 fltNrSamples2
= float(nrSamples2
)
375 for iSample1
in range(nrSamples1
):
376 segPar10
= float(iSample1
) / fltNrSamples1
377 segPar11
= float(iSample1
+ 1) / fltNrSamples1
378 P0
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar10
)
379 P1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar11
)
381 for iSample2
in range(nrSamples2
):
382 segPar20
= float(iSample2
) / fltNrSamples2
383 segPar21
= float(iSample2
+ 1) / fltNrSamples2
384 Q0
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar20
)
385 Q1
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar21
)
387 intersectionPointData
= mathematics
.CalcIntersectionPointsLineSegmentsDIR(P0
, P1
, Q0
, Q1
, algoDIR
)
388 if intersectionPointData
is None:
391 intersectionSegment1Parameter
= segPar10
+ (intersectionPointData
[0] / fltNrSamples1
)
392 worldPoint1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=intersectionSegment1Parameter
)
393 intersectionPoint1
= BezierSegmentIntersectionPoint(self
.segment1
,
394 intersectionSegment1Parameter
,
396 rvIntersections1
.append(intersectionPoint1
)
398 intersectionSegment2Parameter
= segPar20
+ (intersectionPointData
[1] / fltNrSamples2
)
399 worldPoint2
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=intersectionSegment2Parameter
)
400 intersectionPoint2
= BezierSegmentIntersectionPoint(self
.segment2
,
401 intersectionSegment2Parameter
,
403 rvIntersections2
.append(intersectionPoint2
)
405 return [rvIntersections1
, rvIntersections2
]
407 def CalcIntersectionsFromViewPOV(self
, nrSamples1
, nrSamples2
):
410 rvIntersections1
= []
411 rvIntersections2
= []
413 fltNrSamples1
= float(nrSamples1
)
414 fltNrSamples2
= float(nrSamples2
)
416 for iSample1
in range(nrSamples1
):
417 segPar10
= float(iSample1
) / fltNrSamples1
418 segPar11
= float(iSample1
+ 1) / fltNrSamples1
419 P0
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar10
)
420 P1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar11
)
422 for iSample2
in range(nrSamples2
):
423 segPar20
= float(iSample2
) / fltNrSamples2
424 segPar21
= float(iSample2
+ 1) / fltNrSamples2
425 Q0
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar20
)
426 Q1
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar21
)
428 intersectionPointData
= mathematics
.CalcIntersectionPointsLineSegmentsPOV(P0
, P1
, Q0
, Q1
, algoPOV
)
429 if intersectionPointData
is None:
432 intersectionSegment1Parameter
= segPar10
+ (intersectionPointData
[0] / fltNrSamples1
)
433 worldPoint1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=intersectionSegment1Parameter
)
434 intersectionPoint1
= BezierSegmentIntersectionPoint(self
.segment1
,
435 intersectionSegment1Parameter
,
437 rvIntersections1
.append(intersectionPoint1
)
439 intersectionSegment2Parameter
= segPar20
+ (intersectionPointData
[1] / fltNrSamples2
)
440 worldPoint2
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=intersectionSegment2Parameter
)
441 intersectionPoint2
= BezierSegmentIntersectionPoint(self
.segment2
,
442 intersectionSegment2Parameter
,
444 rvIntersections2
.append(intersectionPoint2
)
446 return [rvIntersections1
, rvIntersections2
]
449 class BezierSplineIntersectionPoint
:
450 def __init__(self
, spline
, bezierSegmentIntersectionPoint
):
452 self
.bezierSegmentIntersectionPoint
= bezierSegmentIntersectionPoint
455 class BezierSplinesIntersector
:
456 def __init__(self
, spline1
, spline2
, worldMatrix1
, worldMatrix2
):
457 self
.spline1
= spline1
458 self
.spline2
= spline2
459 self
.worldMatrix1
= worldMatrix1
460 self
.worldMatrix2
= worldMatrix2
462 def CalcIntersections(self
):
463 rvIntersections1
= []
464 rvIntersections2
= []
467 nrSamplesPerSegment1
= int(self
.spline1
.resolution
/ self
.spline1
.nrSegments
)
469 nrSamplesPerSegment1
= 2
470 if nrSamplesPerSegment1
< 2:
471 nrSamplesPerSegment1
= 2
474 nrSamplesPerSegment2
= int(self
.spline2
.resolution
/ self
.spline2
.nrSegments
)
476 nrSamplesPerSegment2
= 2
477 if nrSamplesPerSegment2
< 2:
478 nrSamplesPerSegment2
= 2
480 for segment1
in self
.spline1
.segments
:
481 for segment2
in self
.spline2
.segments
:
482 segmentsIntersector
= BezierSegmentsIntersector(segment1
, segment2
,
483 self
.worldMatrix1
, self
.worldMatrix2
)
484 segmentIntersections
= segmentsIntersector
.CalcIntersections(nrSamplesPerSegment1
, nrSamplesPerSegment2
)
485 if segmentIntersections
is None:
488 segment1Intersections
= segmentIntersections
[0]
489 for segmentIntersection
in segment1Intersections
:
490 splineIntersection
= BezierSplineIntersectionPoint(self
.spline1
, segmentIntersection
)
491 rvIntersections1
.append(splineIntersection
)
493 segment2Intersections
= segmentIntersections
[1]
494 for segmentIntersection
in segment2Intersections
:
495 splineIntersection
= BezierSplineIntersectionPoint(self
.spline2
, segmentIntersection
)
496 rvIntersections2
.append(splineIntersection
)
498 return [rvIntersections1
, rvIntersections2
]
501 class CurvesIntersector
:
504 selObjects
= bpy
.context
.selected_objects
505 if len(selObjects
) != 2:
506 raise Exception("len(selObjects) != 2") # shouldn't be possible
508 blenderActiveCurve
= bpy
.context
.active_object
509 blenderOtherCurve
= selObjects
[0]
510 if blenderActiveCurve
== blenderOtherCurve
:
511 blenderOtherCurve
= selObjects
[1]
513 aCurve
= curves
.Curve(blenderActiveCurve
)
514 oCurve
= curves
.Curve(blenderOtherCurve
)
516 return CurvesIntersector(aCurve
, oCurve
)
527 CurvesIntersector
.ResetGlobals()
531 algo
= bpy
.context
.scene
.curvetools
.IntersectCurvesAlgorithm
532 if algo
== 'From_View':
533 regionView3D
= util
.GetFirstRegionView3D()
534 if regionView3D
is None:
535 print("### ERROR: regionView3D is None. Stopping.")
538 viewPerspective
= regionView3D
.view_perspective
539 print("--", "viewPerspective:", viewPerspective
)
541 if viewPerspective
== 'ORTHO':
542 viewMatrix
= regionView3D
.view_matrix
543 print("--", "viewMatrix:")
546 algoDIR
= Vector((viewMatrix
[2][0], viewMatrix
[2][1], viewMatrix
[2][2]))
547 print("--", "algoDIR:", algoDIR
)
549 # ## TODO: doesn't work properly
550 if viewPerspective
== 'PERSP':
551 viewMatrix
= regionView3D
.view_matrix
552 print("--", "viewMatrix:")
555 algoPOV
= regionView3D
.view_location
.copy()
556 print("--", "algoPOV:", algoPOV
)
558 otherPOV
= Vector((viewMatrix
[0][3], viewMatrix
[1][3], viewMatrix
[2][3]))
559 print("--", "otherPOV:", otherPOV
)
561 localPOV
= Vector((0, 0, 0))
562 globalPOV
= viewMatrix
* localPOV
563 print("--", "globalPOV:", globalPOV
)
565 perspMatrix
= regionView3D
.perspective_matrix
566 print("--", "perspMatrix:")
569 globalPOVPersp
= perspMatrix
* localPOV
570 print("--", "globalPOVPersp:", globalPOVPersp
)
572 if viewPerspective
== 'CAMERA':
573 camera
= bpy
.context
.scene
.camera
575 print("### ERROR: camera is None. Stopping.")
578 print("--", "camera:", camera
)
579 cameraData
= camera
.data
580 print("--", "cameraData.type:", cameraData
.type)
582 cameraMatrix
= camera
.matrix_world
583 print("--", "cameraMatrix:")
586 if cameraData
.type == 'ORTHO':
587 cameraMatrix
= camera
.matrix_world
588 # algoDIR = Vector((cameraMatrix[2][0], cameraMatrix[2][1], cameraMatrix[2][2]))
589 algoDIR
= Vector((- cameraMatrix
[0][2], - cameraMatrix
[1][2], - cameraMatrix
[2][2]))
590 print("--", "algoDIR:", algoDIR
)
592 if cameraData
.type == 'PERSP':
593 algoPOV
= camera
.location
.copy()
594 print("--", "algoPOV:", algoPOV
)
596 def __init__(self
, activeCurve
, otherCurve
):
597 self
.activeCurve
= activeCurve
598 self
.otherCurve
= otherCurve
600 CurvesIntersector
.InitGlobals()
602 def CalcIntersections(self
):
603 rvIntersections1
= []
604 rvIntersections2
= []
606 worldMatrix1
= self
.activeCurve
.curve
.matrix_world
607 worldMatrix2
= self
.otherCurve
.curve
.matrix_world
609 for spline1
in self
.activeCurve
.splines
:
610 for spline2
in self
.otherCurve
.splines
:
611 splineIntersector
= BezierSplinesIntersector(spline1
, spline2
, worldMatrix1
, worldMatrix2
)
612 splineIntersections
= splineIntersector
.CalcIntersections()
613 if splineIntersections
is None:
616 spline1Intersections
= splineIntersections
[0]
617 for splineIntersection
in spline1Intersections
:
618 rvIntersections1
.append(splineIntersection
)
620 spline2Intersections
= splineIntersections
[1]
621 for splineIntersection
in spline2Intersections
:
622 rvIntersections2
.append(splineIntersection
)
624 return [rvIntersections1
, rvIntersections2
]
626 def CalcAndApplyIntersections(self
):
627 mode
= bpy
.context
.scene
.curvetools
.IntersectCurvesMode
630 return self
.CalcAndApplyEmptyAtIntersections()
632 return self
.CalcAndApplyInsertAtIntersections()
634 return self
.CalcAndApplySplitAtIntersections()
638 def CalcAndApplyEmptyAtIntersections(self
):
639 intersections
= self
.CalcIntersections()
640 intersectionsActive
= intersections
[0]
641 intersectionsOther
= intersections
[1]
646 affect
= bpy
.context
.scene
.curvetools
.IntersectCurvesAffect
648 if (affect
== 'Both') or (affect
== 'Active'):
649 for splineIntersection
in intersectionsActive
:
650 iPoint
= splineIntersection
.bezierSegmentIntersectionPoint
.intersectionPoint
651 bpy
.ops
.object.empty_add(type='PLAIN_AXES',
653 location
=(iPoint
.x
, iPoint
.y
, iPoint
.z
), rotation
=(0, 0, 0))
656 if (affect
== 'Both') or (affect
== 'Other'):
657 for splineIntersection
in intersectionsOther
:
658 iPoint
= splineIntersection
.bezierSegmentIntersectionPoint
.intersectionPoint
659 bpy
.ops
.object.empty_add(type='PLAIN_AXES',
661 location
=(iPoint
.x
, iPoint
.y
, iPoint
.z
), rotation
=(0, 0, 0))
664 return [nrActive
, nrOther
]
666 def CalcAndApplyInsertAtIntersections(self
):
670 affect
= bpy
.context
.scene
.curvetools
.IntersectCurvesAffect
671 affectA
= (affect
== 'Both') or (affect
== 'Active')
672 affectO
= (affect
== 'Both') or (affect
== 'Other')
674 for iSplineA
in range(len(self
.activeCurve
.splines
)):
675 splineA
= self
.activeCurve
.splines
[iSplineA
]
676 nrSegmentsA
= len(splineA
.segments
)
677 resPerSegA
= splineA
.resolutionPerSegment
679 for iSplineO
in range(len(self
.otherCurve
.splines
)):
680 splineO
= self
.otherCurve
.splines
[iSplineO
]
681 nrSegmentsO
= len(splineO
.segments
)
682 resPerSegO
= splineO
.resolutionPerSegment
686 segA
= splineA
.segments
[iSegA
]
690 segO
= splineO
.segments
[iSegO
]
692 segIntersector
= BezierSegmentsIntersector(segA
, segO
,
693 self
.activeCurve
.worldMatrix
,
694 self
.otherCurve
.worldMatrix
)
695 segFirstIntersection
= segIntersector
.CalcFirstIntersection(resPerSegA
, resPerSegO
)
697 if segFirstIntersection
is not None:
698 intPointA
= segFirstIntersection
[0]
699 intPointO
= segFirstIntersection
[1]
700 # else does something weird if 1 of them is None..
701 if (intPointA
is not None) and (intPointO
is not None):
703 if intPointA
is not None:
704 splineA
.InsertPoint(segA
, intPointA
.parameter
)
710 if intPointO
is not None:
711 splineO
.InsertPoint(segO
, intPointO
.parameter
)
717 if not (iSegO
< nrSegmentsO
):
721 if not (iSegA
< nrSegmentsA
):
725 splineO
.RefreshInScene()
728 splineA
.RefreshInScene()
730 return [nrActive
, nrOther
]
732 def CalcAndApplySplitAtIntersections(self
):
736 affect
= bpy
.context
.scene
.curvetools
.IntersectCurvesAffect
737 affectA
= (affect
== 'Both') or (affect
== 'Active')
738 affectO
= (affect
== 'Both') or (affect
== 'Other')
740 nrSplinesA
= len(self
.activeCurve
.splines
)
741 nrSplinesO
= len(self
.otherCurve
.splines
)
745 splineA
= self
.activeCurve
.splines
[iSplineA
]
746 nrSegmentsA
= len(splineA
.segments
)
747 resPerSegA
= splineA
.resolutionPerSegment
751 splineO
= self
.otherCurve
.splines
[iSplineO
]
752 nrSegmentsO
= len(splineO
.segments
)
753 resPerSegO
= splineO
.resolutionPerSegment
757 segA
= splineA
.segments
[iSegA
]
761 segO
= splineO
.segments
[iSegO
]
763 segIntersector
= BezierSegmentsIntersector(segA
, segO
,
764 self
.activeCurve
.worldMatrix
,
765 self
.otherCurve
.worldMatrix
)
766 segFirstIntersection
= segIntersector
.CalcFirstIntersection(resPerSegA
, resPerSegO
)
768 if segFirstIntersection
is not None:
769 intPointA
= segFirstIntersection
[0]
770 intPointO
= segFirstIntersection
[1]
771 # else does something weird if 1 of them is None..
772 if (intPointA
is not None) and (intPointO
is not None):
774 if intPointA
is not None:
775 print("--", "splineA.Split():")
776 newSplinesA
= splineA
.Split(segA
, intPointA
.parameter
)
777 if newSplinesA
is not None:
778 newResolutions
= splineA
.CalcDivideResolution(segA
, intPointA
.parameter
)
779 newSplinesA
[0].resolution
= newResolutions
[0]
780 newSplinesA
[1].resolution
= newResolutions
[1]
782 splineA
= newSplinesA
[0]
783 self
.activeCurve
.splines
[iSplineA
] = splineA
784 self
.activeCurve
.splines
.insert(iSplineA
+ 1, newSplinesA
[1])
789 if intPointO
is not None:
790 print("--", "splineO.Split():")
791 newSplinesO
= splineO
.Split(segO
, intPointO
.parameter
)
792 if newSplinesO
is not None:
793 newResolutions
= splineO
.CalcDivideResolution(segO
, intPointO
.parameter
)
794 newSplinesO
[0].resolution
= newResolutions
[0]
795 newSplinesO
[1].resolution
= newResolutions
[1]
797 splineO
= newSplinesO
[0]
798 self
.otherCurve
.splines
[iSplineO
] = splineO
799 self
.otherCurve
.splines
.insert(iSplineO
+ 1, newSplinesO
[1])
803 nrSegmentsO
= len(splineO
.segments
)
805 if not (iSegO
< nrSegmentsO
):
808 nrSegmentsA
= len(splineA
.segments
)
810 if not (iSegA
< nrSegmentsA
):
813 nrSplinesO
= len(self
.otherCurve
.splines
)
815 if not (iSplineO
< nrSplinesO
):
818 nrSplinesA
= len(self
.activeCurve
.splines
)
820 if not (iSplineA
< nrSplinesA
):
825 print("--", "self.activeCurve.RebuildInScene():")
826 self
.activeCurve
.RebuildInScene()
829 print("--", "self.otherCurve.RebuildInScene():")
830 self
.otherCurve
.RebuildInScene()
832 return [nrActive
, nrOther
]