blender-addons/curve_tools/intersections.py
Campbell Barton e8da6131fd License headers: use SPDX-FileCopyrightText for all addons
Move copyright text to SPDX-FileCopyrightText or set to the
Blender Foundation so "make check_licenses" now runs without warnings.
2023-06-15 16:54:05 +10:00

835 lines
38 KiB
Python

# SPDX-FileCopyrightText: 2019-2022 Blender Foundation
#
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
from . import mathematics
from . import curves
from . import util
from mathutils import Vector
algoPOV = None
algoDIR = None
class BezierSegmentIntersectionPoint:
def __init__(self, segment, parameter, intersectionPoint):
self.segment = segment
self.parameter = parameter
self.intersectionPoint = intersectionPoint
class BezierSegmentsIntersector:
def __init__(self, segment1, segment2, worldMatrix1, worldMatrix2):
self.segment1 = segment1
self.segment2 = segment2
self.worldMatrix1 = worldMatrix1
self.worldMatrix2 = worldMatrix2
def CalcFirstIntersection(self, nrSamples1, nrSamples2):
algorithm = bpy.context.scene.curvetools.IntersectCurvesAlgorithm
if algorithm == '3D':
return self.CalcFirstRealIntersection3D(nrSamples1, nrSamples2)
if algorithm == 'From_View':
global algoDIR
if algoDIR is not None:
return self.CalcFirstRealIntersectionFromViewDIR(nrSamples1, nrSamples2)
global algoPOV
if algoPOV is not None:
return self.CalcFirstRealIntersectionFromViewPOV(nrSamples1, nrSamples2)
return None
def CalcFirstIntersection3D(self, nrSamples1, nrSamples2):
fltNrSamples1 = float(nrSamples1)
fltNrSamples2 = float(nrSamples2)
limitDistance = bpy.context.scene.curvetools.LimitDistance
for iSample1 in range(nrSamples1):
segPar10 = float(iSample1) / fltNrSamples1
segPar11 = float(iSample1 + 1) / fltNrSamples1
P0 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar10)
P1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar11)
for iSample2 in range(nrSamples2):
segPar20 = float(iSample2) / fltNrSamples2
segPar21 = float(iSample2 + 1) / fltNrSamples2
Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20)
Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21)
intersectionPointData = mathematics.CalcIntersectionPointLineSegments(P0, P1, Q0, Q1, limitDistance)
if intersectionPointData is None:
continue
intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / fltNrSamples1)
intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1,
intersectionSegment1Parameter,
intersectionPointData[2])
intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / fltNrSamples2)
intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2,
intersectionSegment2Parameter,
intersectionPointData[3])
return [intersectionPoint1, intersectionPoint2]
return None
def CalcFirstRealIntersection3D(self, nrSamples1, nrSamples2):
fltNrSamples1 = float(nrSamples1)
fltNrSamples2 = float(nrSamples2)
limitDistance = bpy.context.scene.curvetools.LimitDistance
for iSample1 in range(nrSamples1):
segPar10 = float(iSample1) / fltNrSamples1
segPar11 = float(iSample1 + 1) / fltNrSamples1
P0 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar10)
P1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar11)
for iSample2 in range(nrSamples2):
segPar20 = float(iSample2) / fltNrSamples2
segPar21 = float(iSample2 + 1) / fltNrSamples2
Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20)
Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21)
intersectionPointData = mathematics.CalcIntersectionPointLineSegments(P0, P1, Q0, Q1, limitDistance)
if intersectionPointData is None:
continue
# intersection point can't be an existing point
intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / (fltNrSamples1))
worldPoint1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
if (mathematics.IsSamePoint(P0, worldPoint1, limitDistance)) or \
(mathematics.IsSamePoint(P1, worldPoint1, limitDistance)):
intersectionPoint1 = None
else:
intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1,
intersectionSegment1Parameter,
worldPoint1)
intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / (fltNrSamples2))
worldPoint2 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
if (mathematics.IsSamePoint(Q0, worldPoint2, limitDistance)) or \
(mathematics.IsSamePoint(Q1, worldPoint2, limitDistance)):
intersectionPoint2 = None
else:
intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2,
intersectionSegment2Parameter,
worldPoint2)
return [intersectionPoint1, intersectionPoint2]
return None
def CalcFirstIntersectionFromViewDIR(self, nrSamples1, nrSamples2):
global algoDIR
fltNrSamples1 = float(nrSamples1)
fltNrSamples2 = float(nrSamples2)
for iSample1 in range(nrSamples1):
segPar10 = float(iSample1) / fltNrSamples1
segPar11 = float(iSample1 + 1) / fltNrSamples1
P0 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar10)
P1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar11)
for iSample2 in range(nrSamples2):
segPar20 = float(iSample2) / fltNrSamples2
segPar21 = float(iSample2 + 1) / fltNrSamples2
Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20)
Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21)
intersectionPointData = mathematics.CalcIntersectionPointsLineSegmentsDIR(P0, P1, Q0, Q1, algoDIR)
if intersectionPointData is None:
continue
intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / fltNrSamples1)
worldPoint1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1,
intersectionSegment1Parameter,
worldPoint1)
intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / fltNrSamples2)
worldPoint2 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2,
intersectionSegment2Parameter,
worldPoint2)
return [intersectionPoint1, intersectionPoint2]
return None
def CalcFirstRealIntersectionFromViewDIR(self, nrSamples1, nrSamples2):
global algoDIR
fltNrSamples1 = float(nrSamples1)
fltNrSamples2 = float(nrSamples2)
limitDistance = bpy.context.scene.curvetools.LimitDistance
for iSample1 in range(nrSamples1):
segPar10 = float(iSample1) / fltNrSamples1
segPar11 = float(iSample1 + 1) / fltNrSamples1
P0 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar10)
P1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar11)
for iSample2 in range(nrSamples2):
segPar20 = float(iSample2) / fltNrSamples2
segPar21 = float(iSample2 + 1) / fltNrSamples2
Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20)
Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21)
intersectionPointData = mathematics.CalcIntersectionPointsLineSegmentsDIR(P0, P1, Q0, Q1, algoDIR)
if intersectionPointData is None:
continue
# intersection point can't be an existing point
intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / (fltNrSamples1))
worldPoint1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
if (mathematics.IsSamePoint(P0, worldPoint1, limitDistance)) or \
(mathematics.IsSamePoint(P1, worldPoint1, limitDistance)):
intersectionPoint1 = None
else:
intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1,
intersectionSegment1Parameter,
worldPoint1)
intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / (fltNrSamples2))
worldPoint2 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
if (mathematics.IsSamePoint(Q0, worldPoint2, limitDistance)) or \
(mathematics.IsSamePoint(Q1, worldPoint2, limitDistance)):
intersectionPoint2 = None
else:
intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2,
intersectionSegment2Parameter,
worldPoint2)
return [intersectionPoint1, intersectionPoint2]
return None
def CalcFirstIntersectionFromViewPOV(self, nrSamples1, nrSamples2):
global algoPOV
fltNrSamples1 = float(nrSamples1)
fltNrSamples2 = float(nrSamples2)
for iSample1 in range(nrSamples1):
segPar10 = float(iSample1) / fltNrSamples1
segPar11 = float(iSample1 + 1) / fltNrSamples1
P0 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar10)
P1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar11)
for iSample2 in range(nrSamples2):
segPar20 = float(iSample2) / fltNrSamples2
segPar21 = float(iSample2 + 1) / fltNrSamples2
Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20)
Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21)
intersectionPointData = mathematics.CalcIntersectionPointsLineSegmentsPOV(P0, P1, Q0, Q1, algoPOV)
if intersectionPointData is None:
continue
intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / fltNrSamples1)
worldPoint1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1,
intersectionSegment1Parameter,
worldPoint1)
intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / fltNrSamples2)
worldPoint2 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2,
intersectionSegment2Parameter,
worldPoint2)
return [intersectionPoint1, intersectionPoint2]
return None
def CalcFirstRealIntersectionFromViewPOV(self, nrSamples1, nrSamples2):
global algoPOV
fltNrSamples1 = float(nrSamples1)
fltNrSamples2 = float(nrSamples2)
limitDistance = bpy.context.scene.curvetools.LimitDistance
for iSample1 in range(nrSamples1):
segPar10 = float(iSample1) / fltNrSamples1
segPar11 = float(iSample1 + 1) / fltNrSamples1
P0 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar10)
P1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar11)
for iSample2 in range(nrSamples2):
segPar20 = float(iSample2) / fltNrSamples2
segPar21 = float(iSample2 + 1) / fltNrSamples2
Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20)
Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21)
intersectionPointData = mathematics.CalcIntersectionPointsLineSegmentsPOV(P0, P1, Q0, Q1, algoPOV)
if intersectionPointData is None:
continue
# intersection point can't be an existing point
intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / fltNrSamples1)
worldPoint1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
if (mathematics.IsSamePoint(P0, worldPoint1, limitDistance)) or \
(mathematics.IsSamePoint(P1, worldPoint1, limitDistance)):
intersectionPoint1 = None
else:
intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1,
intersectionSegment1Parameter,
worldPoint1)
intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / fltNrSamples2)
worldPoint2 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
if (mathematics.IsSamePoint(Q0, worldPoint2, limitDistance)) or \
(mathematics.IsSamePoint(Q1, worldPoint2, limitDistance)):
intersectionPoint2 = None
else:
intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2,
intersectionSegment2Parameter,
worldPoint2)
return [intersectionPoint1, intersectionPoint2]
return None
def CalcIntersections(self, nrSamples1, nrSamples2):
algorithm = bpy.context.scene.curvetools.IntersectCurvesAlgorithm
if algorithm == '3D':
return self.CalcIntersections3D(nrSamples1, nrSamples2)
if algorithm == 'From_View':
global algoDIR
if algoDIR is not None:
return self.CalcIntersectionsFromViewDIR(nrSamples1, nrSamples2)
global algoPOV
if algoPOV is not None:
return self.CalcIntersectionsFromViewPOV(nrSamples1, nrSamples2)
return [[], []]
def CalcIntersections3D(self, nrSamples1, nrSamples2):
rvIntersections1 = []
rvIntersections2 = []
fltNrSamples1 = float(nrSamples1)
fltNrSamples2 = float(nrSamples2)
limitDistance = bpy.context.scene.curvetools.LimitDistance
for iSample1 in range(nrSamples1):
segPar10 = float(iSample1) / fltNrSamples1
segPar11 = float(iSample1 + 1) / fltNrSamples1
P0 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar10)
P1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar11)
for iSample2 in range(nrSamples2):
segPar20 = float(iSample2) / fltNrSamples2
segPar21 = float(iSample2 + 1) / fltNrSamples2
Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20)
Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21)
intersectionPointData = mathematics.CalcIntersectionPointLineSegments(P0, P1, Q0, Q1, limitDistance)
if intersectionPointData is None:
continue
intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / fltNrSamples1)
worldPoint1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1,
intersectionSegment1Parameter,
worldPoint1)
rvIntersections1.append(intersectionPoint1)
intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / fltNrSamples2)
worldPoint2 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2,
intersectionSegment2Parameter,
worldPoint2)
rvIntersections2.append(intersectionPoint2)
return [rvIntersections1, rvIntersections2]
def CalcIntersectionsFromViewDIR(self, nrSamples1, nrSamples2):
global algoDIR
rvIntersections1 = []
rvIntersections2 = []
fltNrSamples1 = float(nrSamples1)
fltNrSamples2 = float(nrSamples2)
for iSample1 in range(nrSamples1):
segPar10 = float(iSample1) / fltNrSamples1
segPar11 = float(iSample1 + 1) / fltNrSamples1
P0 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar10)
P1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar11)
for iSample2 in range(nrSamples2):
segPar20 = float(iSample2) / fltNrSamples2
segPar21 = float(iSample2 + 1) / fltNrSamples2
Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20)
Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21)
intersectionPointData = mathematics.CalcIntersectionPointsLineSegmentsDIR(P0, P1, Q0, Q1, algoDIR)
if intersectionPointData is None:
continue
intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / fltNrSamples1)
worldPoint1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1,
intersectionSegment1Parameter,
worldPoint1)
rvIntersections1.append(intersectionPoint1)
intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / fltNrSamples2)
worldPoint2 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2,
intersectionSegment2Parameter,
worldPoint2)
rvIntersections2.append(intersectionPoint2)
return [rvIntersections1, rvIntersections2]
def CalcIntersectionsFromViewPOV(self, nrSamples1, nrSamples2):
global algoPOV
rvIntersections1 = []
rvIntersections2 = []
fltNrSamples1 = float(nrSamples1)
fltNrSamples2 = float(nrSamples2)
for iSample1 in range(nrSamples1):
segPar10 = float(iSample1) / fltNrSamples1
segPar11 = float(iSample1 + 1) / fltNrSamples1
P0 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar10)
P1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar11)
for iSample2 in range(nrSamples2):
segPar20 = float(iSample2) / fltNrSamples2
segPar21 = float(iSample2 + 1) / fltNrSamples2
Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20)
Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21)
intersectionPointData = mathematics.CalcIntersectionPointsLineSegmentsPOV(P0, P1, Q0, Q1, algoPOV)
if intersectionPointData is None:
continue
intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / fltNrSamples1)
worldPoint1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1,
intersectionSegment1Parameter,
worldPoint1)
rvIntersections1.append(intersectionPoint1)
intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / fltNrSamples2)
worldPoint2 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2,
intersectionSegment2Parameter,
worldPoint2)
rvIntersections2.append(intersectionPoint2)
return [rvIntersections1, rvIntersections2]
class BezierSplineIntersectionPoint:
def __init__(self, spline, bezierSegmentIntersectionPoint):
self.spline = spline
self.bezierSegmentIntersectionPoint = bezierSegmentIntersectionPoint
class BezierSplinesIntersector:
def __init__(self, spline1, spline2, worldMatrix1, worldMatrix2):
self.spline1 = spline1
self.spline2 = spline2
self.worldMatrix1 = worldMatrix1
self.worldMatrix2 = worldMatrix2
def CalcIntersections(self):
rvIntersections1 = []
rvIntersections2 = []
try:
nrSamplesPerSegment1 = int(self.spline1.resolution / self.spline1.nrSegments)
except:
nrSamplesPerSegment1 = 2
if nrSamplesPerSegment1 < 2:
nrSamplesPerSegment1 = 2
try:
nrSamplesPerSegment2 = int(self.spline2.resolution / self.spline2.nrSegments)
except:
nrSamplesPerSegment2 = 2
if nrSamplesPerSegment2 < 2:
nrSamplesPerSegment2 = 2
for segment1 in self.spline1.segments:
for segment2 in self.spline2.segments:
segmentsIntersector = BezierSegmentsIntersector(segment1, segment2,
self.worldMatrix1, self.worldMatrix2)
segmentIntersections = segmentsIntersector.CalcIntersections(nrSamplesPerSegment1, nrSamplesPerSegment2)
if segmentIntersections is None:
continue
segment1Intersections = segmentIntersections[0]
for segmentIntersection in segment1Intersections:
splineIntersection = BezierSplineIntersectionPoint(self.spline1, segmentIntersection)
rvIntersections1.append(splineIntersection)
segment2Intersections = segmentIntersections[1]
for segmentIntersection in segment2Intersections:
splineIntersection = BezierSplineIntersectionPoint(self.spline2, segmentIntersection)
rvIntersections2.append(splineIntersection)
return [rvIntersections1, rvIntersections2]
class CurvesIntersector:
@staticmethod
def FromSelection():
selObjects = bpy.context.selected_objects
if len(selObjects) != 2:
raise Exception("len(selObjects) != 2") # shouldn't be possible
blenderActiveCurve = bpy.context.active_object
blenderOtherCurve = selObjects[0]
if blenderActiveCurve == blenderOtherCurve:
blenderOtherCurve = selObjects[1]
aCurve = curves.Curve(blenderActiveCurve)
oCurve = curves.Curve(blenderOtherCurve)
return CurvesIntersector(aCurve, oCurve)
@staticmethod
def ResetGlobals():
global algoPOV
algoPOV = None
global algoDIR
algoDIR = None
@staticmethod
def InitGlobals():
CurvesIntersector.ResetGlobals()
global algoPOV
global algoDIR
algo = bpy.context.scene.curvetools.IntersectCurvesAlgorithm
if algo == 'From_View':
regionView3D = util.GetFirstRegionView3D()
if regionView3D is None:
print("### ERROR: regionView3D is None. Stopping.")
return
viewPerspective = regionView3D.view_perspective
print("--", "viewPerspective:", viewPerspective)
if viewPerspective == 'ORTHO':
viewMatrix = regionView3D.view_matrix
print("--", "viewMatrix:")
print(viewMatrix)
algoDIR = Vector((viewMatrix[2][0], viewMatrix[2][1], viewMatrix[2][2]))
print("--", "algoDIR:", algoDIR)
# ## TODO: doesn't work properly
if viewPerspective == 'PERSP':
viewMatrix = regionView3D.view_matrix
print("--", "viewMatrix:")
print(viewMatrix)
algoPOV = regionView3D.view_location.copy()
print("--", "algoPOV:", algoPOV)
otherPOV = Vector((viewMatrix[0][3], viewMatrix[1][3], viewMatrix[2][3]))
print("--", "otherPOV:", otherPOV)
localPOV = Vector((0, 0, 0))
globalPOV = viewMatrix * localPOV
print("--", "globalPOV:", globalPOV)
perspMatrix = regionView3D.perspective_matrix
print("--", "perspMatrix:")
print(perspMatrix)
globalPOVPersp = perspMatrix * localPOV
print("--", "globalPOVPersp:", globalPOVPersp)
if viewPerspective == 'CAMERA':
camera = bpy.context.scene.camera
if camera is None:
print("### ERROR: camera is None. Stopping.")
return
print("--", "camera:", camera)
cameraData = camera.data
print("--", "cameraData.type:", cameraData.type)
cameraMatrix = camera.matrix_world
print("--", "cameraMatrix:")
print(cameraMatrix)
if cameraData.type == 'ORTHO':
cameraMatrix = camera.matrix_world
# algoDIR = Vector((cameraMatrix[2][0], cameraMatrix[2][1], cameraMatrix[2][2]))
algoDIR = Vector((- cameraMatrix[0][2], - cameraMatrix[1][2], - cameraMatrix[2][2]))
print("--", "algoDIR:", algoDIR)
if cameraData.type == 'PERSP':
algoPOV = camera.location.copy()
print("--", "algoPOV:", algoPOV)
def __init__(self, activeCurve, otherCurve):
self.activeCurve = activeCurve
self.otherCurve = otherCurve
CurvesIntersector.InitGlobals()
def CalcIntersections(self):
rvIntersections1 = []
rvIntersections2 = []
worldMatrix1 = self.activeCurve.curve.matrix_world
worldMatrix2 = self.otherCurve.curve.matrix_world
for spline1 in self.activeCurve.splines:
for spline2 in self.otherCurve.splines:
splineIntersector = BezierSplinesIntersector(spline1, spline2, worldMatrix1, worldMatrix2)
splineIntersections = splineIntersector.CalcIntersections()
if splineIntersections is None:
continue
spline1Intersections = splineIntersections[0]
for splineIntersection in spline1Intersections:
rvIntersections1.append(splineIntersection)
spline2Intersections = splineIntersections[1]
for splineIntersection in spline2Intersections:
rvIntersections2.append(splineIntersection)
return [rvIntersections1, rvIntersections2]
def CalcAndApplyIntersections(self):
mode = bpy.context.scene.curvetools.IntersectCurvesMode
if mode == 'Empty':
return self.CalcAndApplyEmptyAtIntersections()
if mode == 'Insert':
return self.CalcAndApplyInsertAtIntersections()
if mode == 'Split':
return self.CalcAndApplySplitAtIntersections()
return [0, 0]
def CalcAndApplyEmptyAtIntersections(self):
intersections = self.CalcIntersections()
intersectionsActive = intersections[0]
intersectionsOther = intersections[1]
nrActive = 0
nrOther = 0
affect = bpy.context.scene.curvetools.IntersectCurvesAffect
if (affect == 'Both') or (affect == 'Active'):
for splineIntersection in intersectionsActive:
iPoint = splineIntersection.bezierSegmentIntersectionPoint.intersectionPoint
bpy.ops.object.empty_add(type='PLAIN_AXES',
align='WORLD',
location=(iPoint.x, iPoint.y, iPoint.z), rotation=(0, 0, 0))
nrActive += 1
if (affect == 'Both') or (affect == 'Other'):
for splineIntersection in intersectionsOther:
iPoint = splineIntersection.bezierSegmentIntersectionPoint.intersectionPoint
bpy.ops.object.empty_add(type='PLAIN_AXES',
align='WORLD',
location=(iPoint.x, iPoint.y, iPoint.z), rotation=(0, 0, 0))
nrOther += 1
return [nrActive, nrOther]
def CalcAndApplyInsertAtIntersections(self):
nrActive = 0
nrOther = 0
affect = bpy.context.scene.curvetools.IntersectCurvesAffect
affectA = (affect == 'Both') or (affect == 'Active')
affectO = (affect == 'Both') or (affect == 'Other')
for iSplineA in range(len(self.activeCurve.splines)):
splineA = self.activeCurve.splines[iSplineA]
nrSegmentsA = len(splineA.segments)
resPerSegA = splineA.resolutionPerSegment
for iSplineO in range(len(self.otherCurve.splines)):
splineO = self.otherCurve.splines[iSplineO]
nrSegmentsO = len(splineO.segments)
resPerSegO = splineO.resolutionPerSegment
iSegA = 0
while True:
segA = splineA.segments[iSegA]
iSegO = 0
while True:
segO = splineO.segments[iSegO]
segIntersector = BezierSegmentsIntersector(segA, segO,
self.activeCurve.worldMatrix,
self.otherCurve.worldMatrix)
segFirstIntersection = segIntersector.CalcFirstIntersection(resPerSegA, resPerSegO)
if segFirstIntersection is not None:
intPointA = segFirstIntersection[0]
intPointO = segFirstIntersection[1]
# else does something weird if 1 of them is None..
if (intPointA is not None) and (intPointO is not None):
if affectA:
if intPointA is not None:
splineA.InsertPoint(segA, intPointA.parameter)
nrActive += 1
nrSegmentsA += 1
if affectO:
if intPointO is not None:
splineO.InsertPoint(segO, intPointO.parameter)
nrOther += 1
nrSegmentsO += 1
iSegO += 1
if not (iSegO < nrSegmentsO):
break
iSegA += 1
if not (iSegA < nrSegmentsA):
break
if affectO:
splineO.RefreshInScene()
if affectA:
splineA.RefreshInScene()
return [nrActive, nrOther]
def CalcAndApplySplitAtIntersections(self):
nrActive = 0
nrOther = 0
affect = bpy.context.scene.curvetools.IntersectCurvesAffect
affectA = (affect == 'Both') or (affect == 'Active')
affectO = (affect == 'Both') or (affect == 'Other')
nrSplinesA = len(self.activeCurve.splines)
nrSplinesO = len(self.otherCurve.splines)
iSplineA = 0
while True:
splineA = self.activeCurve.splines[iSplineA]
nrSegmentsA = len(splineA.segments)
resPerSegA = splineA.resolutionPerSegment
iSplineO = 0
while True:
splineO = self.otherCurve.splines[iSplineO]
nrSegmentsO = len(splineO.segments)
resPerSegO = splineO.resolutionPerSegment
iSegA = 0
while True:
segA = splineA.segments[iSegA]
iSegO = 0
while True:
segO = splineO.segments[iSegO]
segIntersector = BezierSegmentsIntersector(segA, segO,
self.activeCurve.worldMatrix,
self.otherCurve.worldMatrix)
segFirstIntersection = segIntersector.CalcFirstIntersection(resPerSegA, resPerSegO)
if segFirstIntersection is not None:
intPointA = segFirstIntersection[0]
intPointO = segFirstIntersection[1]
# else does something weird if 1 of them is None..
if (intPointA is not None) and (intPointO is not None):
if affectA:
if intPointA is not None:
print("--", "splineA.Split():")
newSplinesA = splineA.Split(segA, intPointA.parameter)
if newSplinesA is not None:
newResolutions = splineA.CalcDivideResolution(segA, intPointA.parameter)
newSplinesA[0].resolution = newResolutions[0]
newSplinesA[1].resolution = newResolutions[1]
splineA = newSplinesA[0]
self.activeCurve.splines[iSplineA] = splineA
self.activeCurve.splines.insert(iSplineA + 1, newSplinesA[1])
nrActive += 1
if affectO:
if intPointO is not None:
print("--", "splineO.Split():")
newSplinesO = splineO.Split(segO, intPointO.parameter)
if newSplinesO is not None:
newResolutions = splineO.CalcDivideResolution(segO, intPointO.parameter)
newSplinesO[0].resolution = newResolutions[0]
newSplinesO[1].resolution = newResolutions[1]
splineO = newSplinesO[0]
self.otherCurve.splines[iSplineO] = splineO
self.otherCurve.splines.insert(iSplineO + 1, newSplinesO[1])
nrOther += 1
nrSegmentsO = len(splineO.segments)
iSegO += 1
if not (iSegO < nrSegmentsO):
break
nrSegmentsA = len(splineA.segments)
iSegA += 1
if not (iSegA < nrSegmentsA):
break
nrSplinesO = len(self.otherCurve.splines)
iSplineO += 1
if not (iSplineO < nrSplinesO):
break
nrSplinesA = len(self.activeCurve.splines)
iSplineA += 1
if not (iSplineA < nrSplinesA):
break
if affectA:
print("")
print("--", "self.activeCurve.RebuildInScene():")
self.activeCurve.RebuildInScene()
if affectO:
print("")
print("--", "self.otherCurve.RebuildInScene():")
self.otherCurve.RebuildInScene()
return [nrActive, nrOther]