1 # SPDX-FileCopyrightText: 2019-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
6 from . import mathematics
10 from mathutils
import Vector
16 class BezierSegmentIntersectionPoint
:
17 def __init__(self
, segment
, parameter
, intersectionPoint
):
18 self
.segment
= segment
19 self
.parameter
= parameter
20 self
.intersectionPoint
= intersectionPoint
23 class BezierSegmentsIntersector
:
24 def __init__(self
, segment1
, segment2
, worldMatrix1
, worldMatrix2
):
25 self
.segment1
= segment1
26 self
.segment2
= segment2
27 self
.worldMatrix1
= worldMatrix1
28 self
.worldMatrix2
= worldMatrix2
30 def CalcFirstIntersection(self
, nrSamples1
, nrSamples2
):
31 algorithm
= bpy
.context
.scene
.curvetools
.IntersectCurvesAlgorithm
34 return self
.CalcFirstRealIntersection3D(nrSamples1
, nrSamples2
)
36 if algorithm
== 'From_View':
38 if algoDIR
is not None:
39 return self
.CalcFirstRealIntersectionFromViewDIR(nrSamples1
, nrSamples2
)
42 if algoPOV
is not None:
43 return self
.CalcFirstRealIntersectionFromViewPOV(nrSamples1
, nrSamples2
)
47 def CalcFirstIntersection3D(self
, nrSamples1
, nrSamples2
):
48 fltNrSamples1
= float(nrSamples1
)
49 fltNrSamples2
= float(nrSamples2
)
51 limitDistance
= bpy
.context
.scene
.curvetools
.LimitDistance
53 for iSample1
in range(nrSamples1
):
54 segPar10
= float(iSample1
) / fltNrSamples1
55 segPar11
= float(iSample1
+ 1) / fltNrSamples1
56 P0
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar10
)
57 P1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar11
)
59 for iSample2
in range(nrSamples2
):
60 segPar20
= float(iSample2
) / fltNrSamples2
61 segPar21
= float(iSample2
+ 1) / fltNrSamples2
62 Q0
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar20
)
63 Q1
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar21
)
65 intersectionPointData
= mathematics
.CalcIntersectionPointLineSegments(P0
, P1
, Q0
, Q1
, limitDistance
)
66 if intersectionPointData
is None:
69 intersectionSegment1Parameter
= segPar10
+ (intersectionPointData
[0] / fltNrSamples1
)
70 intersectionPoint1
= BezierSegmentIntersectionPoint(self
.segment1
,
71 intersectionSegment1Parameter
,
72 intersectionPointData
[2])
74 intersectionSegment2Parameter
= segPar20
+ (intersectionPointData
[1] / fltNrSamples2
)
75 intersectionPoint2
= BezierSegmentIntersectionPoint(self
.segment2
,
76 intersectionSegment2Parameter
,
77 intersectionPointData
[3])
79 return [intersectionPoint1
, intersectionPoint2
]
83 def CalcFirstRealIntersection3D(self
, nrSamples1
, nrSamples2
):
84 fltNrSamples1
= float(nrSamples1
)
85 fltNrSamples2
= float(nrSamples2
)
87 limitDistance
= bpy
.context
.scene
.curvetools
.LimitDistance
89 for iSample1
in range(nrSamples1
):
90 segPar10
= float(iSample1
) / fltNrSamples1
91 segPar11
= float(iSample1
+ 1) / fltNrSamples1
92 P0
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar10
)
93 P1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar11
)
95 for iSample2
in range(nrSamples2
):
96 segPar20
= float(iSample2
) / fltNrSamples2
97 segPar21
= float(iSample2
+ 1) / fltNrSamples2
98 Q0
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar20
)
99 Q1
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar21
)
101 intersectionPointData
= mathematics
.CalcIntersectionPointLineSegments(P0
, P1
, Q0
, Q1
, limitDistance
)
102 if intersectionPointData
is None:
105 # intersection point can't be an existing point
106 intersectionSegment1Parameter
= segPar10
+ (intersectionPointData
[0] / (fltNrSamples1
))
107 worldPoint1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=intersectionSegment1Parameter
)
108 if (mathematics
.IsSamePoint(P0
, worldPoint1
, limitDistance
)) or \
109 (mathematics
.IsSamePoint(P1
, worldPoint1
, limitDistance
)):
111 intersectionPoint1
= None
113 intersectionPoint1
= BezierSegmentIntersectionPoint(self
.segment1
,
114 intersectionSegment1Parameter
,
117 intersectionSegment2Parameter
= segPar20
+ (intersectionPointData
[1] / (fltNrSamples2
))
118 worldPoint2
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=intersectionSegment2Parameter
)
119 if (mathematics
.IsSamePoint(Q0
, worldPoint2
, limitDistance
)) or \
120 (mathematics
.IsSamePoint(Q1
, worldPoint2
, limitDistance
)):
122 intersectionPoint2
= None
124 intersectionPoint2
= BezierSegmentIntersectionPoint(self
.segment2
,
125 intersectionSegment2Parameter
,
128 return [intersectionPoint1
, intersectionPoint2
]
132 def CalcFirstIntersectionFromViewDIR(self
, nrSamples1
, nrSamples2
):
135 fltNrSamples1
= float(nrSamples1
)
136 fltNrSamples2
= float(nrSamples2
)
138 for iSample1
in range(nrSamples1
):
139 segPar10
= float(iSample1
) / fltNrSamples1
140 segPar11
= float(iSample1
+ 1) / fltNrSamples1
141 P0
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar10
)
142 P1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar11
)
144 for iSample2
in range(nrSamples2
):
145 segPar20
= float(iSample2
) / fltNrSamples2
146 segPar21
= float(iSample2
+ 1) / fltNrSamples2
147 Q0
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar20
)
148 Q1
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar21
)
150 intersectionPointData
= mathematics
.CalcIntersectionPointsLineSegmentsDIR(P0
, P1
, Q0
, Q1
, algoDIR
)
151 if intersectionPointData
is None:
154 intersectionSegment1Parameter
= segPar10
+ (intersectionPointData
[0] / fltNrSamples1
)
155 worldPoint1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=intersectionSegment1Parameter
)
156 intersectionPoint1
= BezierSegmentIntersectionPoint(self
.segment1
,
157 intersectionSegment1Parameter
,
160 intersectionSegment2Parameter
= segPar20
+ (intersectionPointData
[1] / fltNrSamples2
)
161 worldPoint2
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=intersectionSegment2Parameter
)
162 intersectionPoint2
= BezierSegmentIntersectionPoint(self
.segment2
,
163 intersectionSegment2Parameter
,
166 return [intersectionPoint1
, intersectionPoint2
]
170 def CalcFirstRealIntersectionFromViewDIR(self
, nrSamples1
, nrSamples2
):
173 fltNrSamples1
= float(nrSamples1
)
174 fltNrSamples2
= float(nrSamples2
)
176 limitDistance
= bpy
.context
.scene
.curvetools
.LimitDistance
178 for iSample1
in range(nrSamples1
):
179 segPar10
= float(iSample1
) / fltNrSamples1
180 segPar11
= float(iSample1
+ 1) / fltNrSamples1
181 P0
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar10
)
182 P1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar11
)
184 for iSample2
in range(nrSamples2
):
185 segPar20
= float(iSample2
) / fltNrSamples2
186 segPar21
= float(iSample2
+ 1) / fltNrSamples2
187 Q0
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar20
)
188 Q1
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar21
)
190 intersectionPointData
= mathematics
.CalcIntersectionPointsLineSegmentsDIR(P0
, P1
, Q0
, Q1
, algoDIR
)
191 if intersectionPointData
is None:
194 # intersection point can't be an existing point
195 intersectionSegment1Parameter
= segPar10
+ (intersectionPointData
[0] / (fltNrSamples1
))
196 worldPoint1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=intersectionSegment1Parameter
)
197 if (mathematics
.IsSamePoint(P0
, worldPoint1
, limitDistance
)) or \
198 (mathematics
.IsSamePoint(P1
, worldPoint1
, limitDistance
)):
200 intersectionPoint1
= None
202 intersectionPoint1
= BezierSegmentIntersectionPoint(self
.segment1
,
203 intersectionSegment1Parameter
,
206 intersectionSegment2Parameter
= segPar20
+ (intersectionPointData
[1] / (fltNrSamples2
))
207 worldPoint2
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=intersectionSegment2Parameter
)
208 if (mathematics
.IsSamePoint(Q0
, worldPoint2
, limitDistance
)) or \
209 (mathematics
.IsSamePoint(Q1
, worldPoint2
, limitDistance
)):
211 intersectionPoint2
= None
213 intersectionPoint2
= BezierSegmentIntersectionPoint(self
.segment2
,
214 intersectionSegment2Parameter
,
217 return [intersectionPoint1
, intersectionPoint2
]
221 def CalcFirstIntersectionFromViewPOV(self
, nrSamples1
, nrSamples2
):
224 fltNrSamples1
= float(nrSamples1
)
225 fltNrSamples2
= float(nrSamples2
)
227 for iSample1
in range(nrSamples1
):
228 segPar10
= float(iSample1
) / fltNrSamples1
229 segPar11
= float(iSample1
+ 1) / fltNrSamples1
230 P0
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar10
)
231 P1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar11
)
233 for iSample2
in range(nrSamples2
):
234 segPar20
= float(iSample2
) / fltNrSamples2
235 segPar21
= float(iSample2
+ 1) / fltNrSamples2
236 Q0
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar20
)
237 Q1
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar21
)
239 intersectionPointData
= mathematics
.CalcIntersectionPointsLineSegmentsPOV(P0
, P1
, Q0
, Q1
, algoPOV
)
240 if intersectionPointData
is None:
243 intersectionSegment1Parameter
= segPar10
+ (intersectionPointData
[0] / fltNrSamples1
)
244 worldPoint1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=intersectionSegment1Parameter
)
245 intersectionPoint1
= BezierSegmentIntersectionPoint(self
.segment1
,
246 intersectionSegment1Parameter
,
249 intersectionSegment2Parameter
= segPar20
+ (intersectionPointData
[1] / fltNrSamples2
)
250 worldPoint2
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=intersectionSegment2Parameter
)
251 intersectionPoint2
= BezierSegmentIntersectionPoint(self
.segment2
,
252 intersectionSegment2Parameter
,
255 return [intersectionPoint1
, intersectionPoint2
]
259 def CalcFirstRealIntersectionFromViewPOV(self
, nrSamples1
, nrSamples2
):
262 fltNrSamples1
= float(nrSamples1
)
263 fltNrSamples2
= float(nrSamples2
)
265 limitDistance
= bpy
.context
.scene
.curvetools
.LimitDistance
267 for iSample1
in range(nrSamples1
):
268 segPar10
= float(iSample1
) / fltNrSamples1
269 segPar11
= float(iSample1
+ 1) / fltNrSamples1
270 P0
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar10
)
271 P1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar11
)
273 for iSample2
in range(nrSamples2
):
274 segPar20
= float(iSample2
) / fltNrSamples2
275 segPar21
= float(iSample2
+ 1) / fltNrSamples2
276 Q0
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar20
)
277 Q1
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar21
)
279 intersectionPointData
= mathematics
.CalcIntersectionPointsLineSegmentsPOV(P0
, P1
, Q0
, Q1
, algoPOV
)
280 if intersectionPointData
is None:
283 # intersection point can't be an existing point
284 intersectionSegment1Parameter
= segPar10
+ (intersectionPointData
[0] / fltNrSamples1
)
285 worldPoint1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=intersectionSegment1Parameter
)
286 if (mathematics
.IsSamePoint(P0
, worldPoint1
, limitDistance
)) or \
287 (mathematics
.IsSamePoint(P1
, worldPoint1
, limitDistance
)):
289 intersectionPoint1
= None
291 intersectionPoint1
= BezierSegmentIntersectionPoint(self
.segment1
,
292 intersectionSegment1Parameter
,
295 intersectionSegment2Parameter
= segPar20
+ (intersectionPointData
[1] / fltNrSamples2
)
296 worldPoint2
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=intersectionSegment2Parameter
)
297 if (mathematics
.IsSamePoint(Q0
, worldPoint2
, limitDistance
)) or \
298 (mathematics
.IsSamePoint(Q1
, worldPoint2
, limitDistance
)):
300 intersectionPoint2
= None
302 intersectionPoint2
= BezierSegmentIntersectionPoint(self
.segment2
,
303 intersectionSegment2Parameter
,
306 return [intersectionPoint1
, intersectionPoint2
]
310 def CalcIntersections(self
, nrSamples1
, nrSamples2
):
311 algorithm
= bpy
.context
.scene
.curvetools
.IntersectCurvesAlgorithm
313 if algorithm
== '3D':
314 return self
.CalcIntersections3D(nrSamples1
, nrSamples2
)
316 if algorithm
== 'From_View':
318 if algoDIR
is not None:
319 return self
.CalcIntersectionsFromViewDIR(nrSamples1
, nrSamples2
)
322 if algoPOV
is not None:
323 return self
.CalcIntersectionsFromViewPOV(nrSamples1
, nrSamples2
)
327 def CalcIntersections3D(self
, nrSamples1
, nrSamples2
):
328 rvIntersections1
= []
329 rvIntersections2
= []
331 fltNrSamples1
= float(nrSamples1
)
332 fltNrSamples2
= float(nrSamples2
)
334 limitDistance
= bpy
.context
.scene
.curvetools
.LimitDistance
336 for iSample1
in range(nrSamples1
):
337 segPar10
= float(iSample1
) / fltNrSamples1
338 segPar11
= float(iSample1
+ 1) / fltNrSamples1
339 P0
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar10
)
340 P1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar11
)
342 for iSample2
in range(nrSamples2
):
343 segPar20
= float(iSample2
) / fltNrSamples2
344 segPar21
= float(iSample2
+ 1) / fltNrSamples2
345 Q0
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar20
)
346 Q1
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar21
)
348 intersectionPointData
= mathematics
.CalcIntersectionPointLineSegments(P0
, P1
, Q0
, Q1
, limitDistance
)
349 if intersectionPointData
is None:
352 intersectionSegment1Parameter
= segPar10
+ (intersectionPointData
[0] / fltNrSamples1
)
353 worldPoint1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=intersectionSegment1Parameter
)
354 intersectionPoint1
= BezierSegmentIntersectionPoint(self
.segment1
,
355 intersectionSegment1Parameter
,
357 rvIntersections1
.append(intersectionPoint1
)
359 intersectionSegment2Parameter
= segPar20
+ (intersectionPointData
[1] / fltNrSamples2
)
360 worldPoint2
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=intersectionSegment2Parameter
)
361 intersectionPoint2
= BezierSegmentIntersectionPoint(self
.segment2
,
362 intersectionSegment2Parameter
,
364 rvIntersections2
.append(intersectionPoint2
)
366 return [rvIntersections1
, rvIntersections2
]
368 def CalcIntersectionsFromViewDIR(self
, nrSamples1
, nrSamples2
):
371 rvIntersections1
= []
372 rvIntersections2
= []
374 fltNrSamples1
= float(nrSamples1
)
375 fltNrSamples2
= float(nrSamples2
)
377 for iSample1
in range(nrSamples1
):
378 segPar10
= float(iSample1
) / fltNrSamples1
379 segPar11
= float(iSample1
+ 1) / fltNrSamples1
380 P0
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar10
)
381 P1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar11
)
383 for iSample2
in range(nrSamples2
):
384 segPar20
= float(iSample2
) / fltNrSamples2
385 segPar21
= float(iSample2
+ 1) / fltNrSamples2
386 Q0
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar20
)
387 Q1
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar21
)
389 intersectionPointData
= mathematics
.CalcIntersectionPointsLineSegmentsDIR(P0
, P1
, Q0
, Q1
, algoDIR
)
390 if intersectionPointData
is None:
393 intersectionSegment1Parameter
= segPar10
+ (intersectionPointData
[0] / fltNrSamples1
)
394 worldPoint1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=intersectionSegment1Parameter
)
395 intersectionPoint1
= BezierSegmentIntersectionPoint(self
.segment1
,
396 intersectionSegment1Parameter
,
398 rvIntersections1
.append(intersectionPoint1
)
400 intersectionSegment2Parameter
= segPar20
+ (intersectionPointData
[1] / fltNrSamples2
)
401 worldPoint2
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=intersectionSegment2Parameter
)
402 intersectionPoint2
= BezierSegmentIntersectionPoint(self
.segment2
,
403 intersectionSegment2Parameter
,
405 rvIntersections2
.append(intersectionPoint2
)
407 return [rvIntersections1
, rvIntersections2
]
409 def CalcIntersectionsFromViewPOV(self
, nrSamples1
, nrSamples2
):
412 rvIntersections1
= []
413 rvIntersections2
= []
415 fltNrSamples1
= float(nrSamples1
)
416 fltNrSamples2
= float(nrSamples2
)
418 for iSample1
in range(nrSamples1
):
419 segPar10
= float(iSample1
) / fltNrSamples1
420 segPar11
= float(iSample1
+ 1) / fltNrSamples1
421 P0
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar10
)
422 P1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=segPar11
)
424 for iSample2
in range(nrSamples2
):
425 segPar20
= float(iSample2
) / fltNrSamples2
426 segPar21
= float(iSample2
+ 1) / fltNrSamples2
427 Q0
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar20
)
428 Q1
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=segPar21
)
430 intersectionPointData
= mathematics
.CalcIntersectionPointsLineSegmentsPOV(P0
, P1
, Q0
, Q1
, algoPOV
)
431 if intersectionPointData
is None:
434 intersectionSegment1Parameter
= segPar10
+ (intersectionPointData
[0] / fltNrSamples1
)
435 worldPoint1
= self
.worldMatrix1
@ self
.segment1
.CalcPoint(parameter
=intersectionSegment1Parameter
)
436 intersectionPoint1
= BezierSegmentIntersectionPoint(self
.segment1
,
437 intersectionSegment1Parameter
,
439 rvIntersections1
.append(intersectionPoint1
)
441 intersectionSegment2Parameter
= segPar20
+ (intersectionPointData
[1] / fltNrSamples2
)
442 worldPoint2
= self
.worldMatrix2
@ self
.segment2
.CalcPoint(parameter
=intersectionSegment2Parameter
)
443 intersectionPoint2
= BezierSegmentIntersectionPoint(self
.segment2
,
444 intersectionSegment2Parameter
,
446 rvIntersections2
.append(intersectionPoint2
)
448 return [rvIntersections1
, rvIntersections2
]
451 class BezierSplineIntersectionPoint
:
452 def __init__(self
, spline
, bezierSegmentIntersectionPoint
):
454 self
.bezierSegmentIntersectionPoint
= bezierSegmentIntersectionPoint
457 class BezierSplinesIntersector
:
458 def __init__(self
, spline1
, spline2
, worldMatrix1
, worldMatrix2
):
459 self
.spline1
= spline1
460 self
.spline2
= spline2
461 self
.worldMatrix1
= worldMatrix1
462 self
.worldMatrix2
= worldMatrix2
464 def CalcIntersections(self
):
465 rvIntersections1
= []
466 rvIntersections2
= []
469 nrSamplesPerSegment1
= int(self
.spline1
.resolution
/ self
.spline1
.nrSegments
)
471 nrSamplesPerSegment1
= 2
472 if nrSamplesPerSegment1
< 2:
473 nrSamplesPerSegment1
= 2
476 nrSamplesPerSegment2
= int(self
.spline2
.resolution
/ self
.spline2
.nrSegments
)
478 nrSamplesPerSegment2
= 2
479 if nrSamplesPerSegment2
< 2:
480 nrSamplesPerSegment2
= 2
482 for segment1
in self
.spline1
.segments
:
483 for segment2
in self
.spline2
.segments
:
484 segmentsIntersector
= BezierSegmentsIntersector(segment1
, segment2
,
485 self
.worldMatrix1
, self
.worldMatrix2
)
486 segmentIntersections
= segmentsIntersector
.CalcIntersections(nrSamplesPerSegment1
, nrSamplesPerSegment2
)
487 if segmentIntersections
is None:
490 segment1Intersections
= segmentIntersections
[0]
491 for segmentIntersection
in segment1Intersections
:
492 splineIntersection
= BezierSplineIntersectionPoint(self
.spline1
, segmentIntersection
)
493 rvIntersections1
.append(splineIntersection
)
495 segment2Intersections
= segmentIntersections
[1]
496 for segmentIntersection
in segment2Intersections
:
497 splineIntersection
= BezierSplineIntersectionPoint(self
.spline2
, segmentIntersection
)
498 rvIntersections2
.append(splineIntersection
)
500 return [rvIntersections1
, rvIntersections2
]
503 class CurvesIntersector
:
506 selObjects
= bpy
.context
.selected_objects
507 if len(selObjects
) != 2:
508 raise Exception("len(selObjects) != 2") # shouldn't be possible
510 blenderActiveCurve
= bpy
.context
.active_object
511 blenderOtherCurve
= selObjects
[0]
512 if blenderActiveCurve
== blenderOtherCurve
:
513 blenderOtherCurve
= selObjects
[1]
515 aCurve
= curves
.Curve(blenderActiveCurve
)
516 oCurve
= curves
.Curve(blenderOtherCurve
)
518 return CurvesIntersector(aCurve
, oCurve
)
529 CurvesIntersector
.ResetGlobals()
533 algo
= bpy
.context
.scene
.curvetools
.IntersectCurvesAlgorithm
534 if algo
== 'From_View':
535 regionView3D
= util
.GetFirstRegionView3D()
536 if regionView3D
is None:
537 print("### ERROR: regionView3D is None. Stopping.")
540 viewPerspective
= regionView3D
.view_perspective
541 print("--", "viewPerspective:", viewPerspective
)
543 if viewPerspective
== 'ORTHO':
544 viewMatrix
= regionView3D
.view_matrix
545 print("--", "viewMatrix:")
548 algoDIR
= Vector((viewMatrix
[2][0], viewMatrix
[2][1], viewMatrix
[2][2]))
549 print("--", "algoDIR:", algoDIR
)
551 # ## TODO: doesn't work properly
552 if viewPerspective
== 'PERSP':
553 viewMatrix
= regionView3D
.view_matrix
554 print("--", "viewMatrix:")
557 algoPOV
= regionView3D
.view_location
.copy()
558 print("--", "algoPOV:", algoPOV
)
560 otherPOV
= Vector((viewMatrix
[0][3], viewMatrix
[1][3], viewMatrix
[2][3]))
561 print("--", "otherPOV:", otherPOV
)
563 localPOV
= Vector((0, 0, 0))
564 globalPOV
= viewMatrix
* localPOV
565 print("--", "globalPOV:", globalPOV
)
567 perspMatrix
= regionView3D
.perspective_matrix
568 print("--", "perspMatrix:")
571 globalPOVPersp
= perspMatrix
* localPOV
572 print("--", "globalPOVPersp:", globalPOVPersp
)
574 if viewPerspective
== 'CAMERA':
575 camera
= bpy
.context
.scene
.camera
577 print("### ERROR: camera is None. Stopping.")
580 print("--", "camera:", camera
)
581 cameraData
= camera
.data
582 print("--", "cameraData.type:", cameraData
.type)
584 cameraMatrix
= camera
.matrix_world
585 print("--", "cameraMatrix:")
588 if cameraData
.type == 'ORTHO':
589 cameraMatrix
= camera
.matrix_world
590 # algoDIR = Vector((cameraMatrix[2][0], cameraMatrix[2][1], cameraMatrix[2][2]))
591 algoDIR
= Vector((- cameraMatrix
[0][2], - cameraMatrix
[1][2], - cameraMatrix
[2][2]))
592 print("--", "algoDIR:", algoDIR
)
594 if cameraData
.type == 'PERSP':
595 algoPOV
= camera
.location
.copy()
596 print("--", "algoPOV:", algoPOV
)
598 def __init__(self
, activeCurve
, otherCurve
):
599 self
.activeCurve
= activeCurve
600 self
.otherCurve
= otherCurve
602 CurvesIntersector
.InitGlobals()
604 def CalcIntersections(self
):
605 rvIntersections1
= []
606 rvIntersections2
= []
608 worldMatrix1
= self
.activeCurve
.curve
.matrix_world
609 worldMatrix2
= self
.otherCurve
.curve
.matrix_world
611 for spline1
in self
.activeCurve
.splines
:
612 for spline2
in self
.otherCurve
.splines
:
613 splineIntersector
= BezierSplinesIntersector(spline1
, spline2
, worldMatrix1
, worldMatrix2
)
614 splineIntersections
= splineIntersector
.CalcIntersections()
615 if splineIntersections
is None:
618 spline1Intersections
= splineIntersections
[0]
619 for splineIntersection
in spline1Intersections
:
620 rvIntersections1
.append(splineIntersection
)
622 spline2Intersections
= splineIntersections
[1]
623 for splineIntersection
in spline2Intersections
:
624 rvIntersections2
.append(splineIntersection
)
626 return [rvIntersections1
, rvIntersections2
]
628 def CalcAndApplyIntersections(self
):
629 mode
= bpy
.context
.scene
.curvetools
.IntersectCurvesMode
632 return self
.CalcAndApplyEmptyAtIntersections()
634 return self
.CalcAndApplyInsertAtIntersections()
636 return self
.CalcAndApplySplitAtIntersections()
640 def CalcAndApplyEmptyAtIntersections(self
):
641 intersections
= self
.CalcIntersections()
642 intersectionsActive
= intersections
[0]
643 intersectionsOther
= intersections
[1]
648 affect
= bpy
.context
.scene
.curvetools
.IntersectCurvesAffect
650 if (affect
== 'Both') or (affect
== 'Active'):
651 for splineIntersection
in intersectionsActive
:
652 iPoint
= splineIntersection
.bezierSegmentIntersectionPoint
.intersectionPoint
653 bpy
.ops
.object.empty_add(type='PLAIN_AXES',
655 location
=(iPoint
.x
, iPoint
.y
, iPoint
.z
), rotation
=(0, 0, 0))
658 if (affect
== 'Both') or (affect
== 'Other'):
659 for splineIntersection
in intersectionsOther
:
660 iPoint
= splineIntersection
.bezierSegmentIntersectionPoint
.intersectionPoint
661 bpy
.ops
.object.empty_add(type='PLAIN_AXES',
663 location
=(iPoint
.x
, iPoint
.y
, iPoint
.z
), rotation
=(0, 0, 0))
666 return [nrActive
, nrOther
]
668 def CalcAndApplyInsertAtIntersections(self
):
672 affect
= bpy
.context
.scene
.curvetools
.IntersectCurvesAffect
673 affectA
= (affect
== 'Both') or (affect
== 'Active')
674 affectO
= (affect
== 'Both') or (affect
== 'Other')
676 for iSplineA
in range(len(self
.activeCurve
.splines
)):
677 splineA
= self
.activeCurve
.splines
[iSplineA
]
678 nrSegmentsA
= len(splineA
.segments
)
679 resPerSegA
= splineA
.resolutionPerSegment
681 for iSplineO
in range(len(self
.otherCurve
.splines
)):
682 splineO
= self
.otherCurve
.splines
[iSplineO
]
683 nrSegmentsO
= len(splineO
.segments
)
684 resPerSegO
= splineO
.resolutionPerSegment
688 segA
= splineA
.segments
[iSegA
]
692 segO
= splineO
.segments
[iSegO
]
694 segIntersector
= BezierSegmentsIntersector(segA
, segO
,
695 self
.activeCurve
.worldMatrix
,
696 self
.otherCurve
.worldMatrix
)
697 segFirstIntersection
= segIntersector
.CalcFirstIntersection(resPerSegA
, resPerSegO
)
699 if segFirstIntersection
is not None:
700 intPointA
= segFirstIntersection
[0]
701 intPointO
= segFirstIntersection
[1]
702 # else does something weird if 1 of them is None..
703 if (intPointA
is not None) and (intPointO
is not None):
705 if intPointA
is not None:
706 splineA
.InsertPoint(segA
, intPointA
.parameter
)
712 if intPointO
is not None:
713 splineO
.InsertPoint(segO
, intPointO
.parameter
)
719 if not (iSegO
< nrSegmentsO
):
723 if not (iSegA
< nrSegmentsA
):
727 splineO
.RefreshInScene()
730 splineA
.RefreshInScene()
732 return [nrActive
, nrOther
]
734 def CalcAndApplySplitAtIntersections(self
):
738 affect
= bpy
.context
.scene
.curvetools
.IntersectCurvesAffect
739 affectA
= (affect
== 'Both') or (affect
== 'Active')
740 affectO
= (affect
== 'Both') or (affect
== 'Other')
742 nrSplinesA
= len(self
.activeCurve
.splines
)
743 nrSplinesO
= len(self
.otherCurve
.splines
)
747 splineA
= self
.activeCurve
.splines
[iSplineA
]
748 nrSegmentsA
= len(splineA
.segments
)
749 resPerSegA
= splineA
.resolutionPerSegment
753 splineO
= self
.otherCurve
.splines
[iSplineO
]
754 nrSegmentsO
= len(splineO
.segments
)
755 resPerSegO
= splineO
.resolutionPerSegment
759 segA
= splineA
.segments
[iSegA
]
763 segO
= splineO
.segments
[iSegO
]
765 segIntersector
= BezierSegmentsIntersector(segA
, segO
,
766 self
.activeCurve
.worldMatrix
,
767 self
.otherCurve
.worldMatrix
)
768 segFirstIntersection
= segIntersector
.CalcFirstIntersection(resPerSegA
, resPerSegO
)
770 if segFirstIntersection
is not None:
771 intPointA
= segFirstIntersection
[0]
772 intPointO
= segFirstIntersection
[1]
773 # else does something weird if 1 of them is None..
774 if (intPointA
is not None) and (intPointO
is not None):
776 if intPointA
is not None:
777 print("--", "splineA.Split():")
778 newSplinesA
= splineA
.Split(segA
, intPointA
.parameter
)
779 if newSplinesA
is not None:
780 newResolutions
= splineA
.CalcDivideResolution(segA
, intPointA
.parameter
)
781 newSplinesA
[0].resolution
= newResolutions
[0]
782 newSplinesA
[1].resolution
= newResolutions
[1]
784 splineA
= newSplinesA
[0]
785 self
.activeCurve
.splines
[iSplineA
] = splineA
786 self
.activeCurve
.splines
.insert(iSplineA
+ 1, newSplinesA
[1])
791 if intPointO
is not None:
792 print("--", "splineO.Split():")
793 newSplinesO
= splineO
.Split(segO
, intPointO
.parameter
)
794 if newSplinesO
is not None:
795 newResolutions
= splineO
.CalcDivideResolution(segO
, intPointO
.parameter
)
796 newSplinesO
[0].resolution
= newResolutions
[0]
797 newSplinesO
[1].resolution
= newResolutions
[1]
799 splineO
= newSplinesO
[0]
800 self
.otherCurve
.splines
[iSplineO
] = splineO
801 self
.otherCurve
.splines
.insert(iSplineO
+ 1, newSplinesO
[1])
805 nrSegmentsO
= len(splineO
.segments
)
807 if not (iSegO
< nrSegmentsO
):
810 nrSegmentsA
= len(splineA
.segments
)
812 if not (iSegA
< nrSegmentsA
):
815 nrSplinesO
= len(self
.otherCurve
.splines
)
817 if not (iSplineO
< nrSplinesO
):
820 nrSplinesA
= len(self
.activeCurve
.splines
)
822 if not (iSplineA
< nrSplinesA
):
827 print("--", "self.activeCurve.RebuildInScene():")
828 self
.activeCurve
.RebuildInScene()
831 print("--", "self.otherCurve.RebuildInScene():")
832 self
.otherCurve
.RebuildInScene()
834 return [nrActive
, nrOther
]