from . import Math
from . import Curves
from . import Util

from mathutils import *

import bpy


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 not algoDIR is None: return self.CalcFirstRealIntersectionFromViewDIR(nrSamples1, nrSamples2)
            
            global algoPOV
            if not algoPOV is 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 = Math.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 = Math.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 (Math.IsSamePoint(P0, worldPoint1, limitDistance)) or (Math.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 (Math.IsSamePoint(Q0, worldPoint2, limitDistance)) or (Math.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 = Math.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 = Math.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 (Math.IsSamePoint(P0, worldPoint1, limitDistance)) or (Math.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 (Math.IsSamePoint(Q0, worldPoint2, limitDistance)) or (Math.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 = Math.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 = Math.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 (Math.IsSamePoint(P0, worldPoint1, limitDistance)) or (Math.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 (Math.IsSamePoint(Q0, worldPoint2, limitDistance)) or (Math.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 not algoDIR is None: return self.CalcIntersectionsFromViewDIR(nrSamples1, nrSamples2)
            
            global algoPOV
            if not algoPOV is 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 = Math.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 = Math.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 = Math.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()
        
        
        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)
                
                global algoDIR
                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)
                
                global algoPOV
                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
                
                    global algoDIR
                    #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':
                    global algoPOV
                    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', view_align=False, 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', view_align=False, 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 not segFirstIntersection is None:
                            intPointA = segFirstIntersection[0]
                            intPointO = segFirstIntersection[1]
                            if (not intPointA is None) and (not intPointO is None):    # else does something weird if 1 of them is None.. 
                                if affectA:
                                    if not intPointA is None:
                                        splineA.InsertPoint(segA, intPointA.parameter)
                                        
                                        nrActive += 1
                                        nrSegmentsA += 1
                                        
                                if affectO:
                                    if not intPointO is 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 not segFirstIntersection is None:
                            intPointA = segFirstIntersection[0]
                            intPointO = segFirstIntersection[1]
                            if (not intPointA is None) and (not intPointO is None):    # else does something weird if 1 of them is None.. 
                                if affectA:
                                    if not intPointA is None:
                                        print("--", "splineA.Split():")
                                        newSplinesA = splineA.Split(segA, intPointA.parameter)
                                        if not newSplinesA is 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 not intPointO is None:
                                        print("--", "splineO.Split():")
                                        newSplinesO = splineO.Split(segO, intPointO.parameter)
                                        if not newSplinesO is 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]
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        