# -*- coding: utf-8 -*-

__title__ = "Combined projection curve"
__author__ = "Christophe Grellier (Chris_G)"
__license__ = "LGPL 2.1"
__doc__ = "Builds a 3D curve as the intersection of 2 projected curves."

import FreeCAD
import FreeCADGui
import Part
import _utils
import approximate_extension

TOOL_ICON = _utils.iconsPath() + 'combined_curve.svg'
debug = _utils.debug
#debug = _utils.doNothing

class CombinedProjectionCurve:
    """Builds a 3D curve as the intersection of 2 projected curves."""
    def __init__(self, sh1, sh2, dir1, dir2):
        self.shape1 = sh1
        self.shape2 = sh2
        if not dir1.Length == 0:
            self.dir1 = dir1
        else:
            raise ValueError("Vector is null")
        if not dir2.Length == 0:
            self.dir2 = dir2
        else:
            raise ValueError("Vector is null")
    def shape(self):
        proj1 = self.shape1.toNurbs().extrude(self.dir1)
        proj2 = self.shape2.toNurbs().extrude(self.dir2)
        curves = list()
        for f1 in proj1.Faces:
            for f2 in proj2.Faces:
                curves += f1.Surface.intersectSS(f2.Surface)
        intersect = [c.toShape() for c in curves]
        edges = []
        for sh in intersect:
            if isinstance(sh, Part.Edge) and sh.Length > 1e-7:
                edges.append(sh)
        se = Part.sortEdges(edges)
        wires = []
        for el in se:
            wires.append(Part.Wire(el))
        return Part.Compound(wires)



class CombinedProjectionCurveFP:
    """Builds a 3D curve as the intersection of 2 projected curves."""
    def __init__(self, obj, s1, s2, d1, d2):
        obj.addProperty("App::PropertyLink", "Shape1", "Combined Projection", "First shape").Shape1 = s1
        obj.addProperty("App::PropertyLink", "Shape2", "Combined Projection", "Second shape").Shape2 = s2
        obj.addProperty("App::PropertyVector", "Direction1", "Combined Projection", "Projection direction of the first shape.\nIf vector is null, shape's placement is used.").Direction1 = d1
        #obj.addProperty("App::PropertyPlacement", "Direction1", "Combined Projection", "Projection direction of the first shape").Direction1 = pl1
        obj.addProperty("App::PropertyVector", "Direction2", "Combined Projection", "Projection direction of the second shape.\nIf vector is null, shape's placement is used.").Direction2 = d2
        obj.Proxy = self

    def execute(self, obj):
        s1 = obj.Shape1.Shape
        s2 = obj.Shape2.Shape
        if obj.Direction1.Length < 1e-7:
            d1 = obj.Shape1.Placement.Rotation.multVec(FreeCAD.Vector(0,0,-1))
        else:
            d1 = obj.Direction1
        if obj.Direction2.Length < 1e-7:
            d2 = obj.Shape2.Placement.Rotation.multVec(FreeCAD.Vector(0,0,-1))
        else:
            d2 = obj.Direction2
        cc = CombinedProjectionCurve(s1,s2,d1,d2)
        if hasattr(obj,"ExtensionProxy"):
            obj.Shape = obj.ExtensionProxy.approximate(obj,cc.shape().Edges)
        else:
            obj.Shape = cc.shape()

    def onChanged(self, fp, prop):
        if hasattr(fp,"ExtensionProxy"):
            fp.ExtensionProxy.onChanged(fp, prop)

class CombinedProjectionCurveVP:
    def __init__(self,vobj):
        vobj.Proxy = self
       
    def getIcon(self):
        return (TOOL_ICON)

    def attach(self, vobj):
        self.Object = vobj.Object

    def __getstate__(self):
        return {"name": self.Object.Name}

    def __setstate__(self,state):
        self.Object = FreeCAD.ActiveDocument.getObject(state["name"])
        return None

    def claimChildren(self):
        return [self.Object.Shape1,self.Object.Shape2]

class CombinedProjectionCmd:
    """Splits the selected edges."""
    def makeCPCFeature(self,o1,o2,d1,d2):
        cc = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Mixed curve")
        CombinedProjectionCurveFP(cc, o1,o2,d1,d2)
        approximate_extension.ApproximateExtension(cc)
        cc.Active = False
        CombinedProjectionCurveVP(cc.ViewObject)
        FreeCAD.ActiveDocument.recompute()

    def Activated(self):
        vd = [FreeCAD.Vector(0,0,0), FreeCAD.Vector(0,0,0)]
        try:
            sel = FreeCADGui.activeWorkbench().Selection
            vd =  FreeCADGui.activeWorkbench().View_Directions
        except AttributeError:
            sel = FreeCADGui.Selection.getSelectionEx()
        if not len(sel) == 2:
            FreeCAD.Console.PrintError("Select 2 objects !\n")
            return
        for selobj in sel:
            selobj.Object.ViewObject.Visibility = False
        if len(vd) == 2 and vd[0].dot(vd[1]) < 0.999:
            d1, d2 = vd
        else:
            d1,d2 = [FreeCAD.Vector(0,0,0), FreeCAD.Vector(0,0,0)]
        self.makeCPCFeature(sel[0].Object,sel[1].Object,d1,d2)
        
    def IsActive(self):
        if FreeCAD.ActiveDocument:
            sel = FreeCADGui.Selection.getSelection()
            if len(sel) == 2:
                return True
        return False

    def GetResources(self):
        return {'Pixmap' : TOOL_ICON, 'MenuText': 'Combined projection curve', 'ToolTip': 'Builds a 3D curve as the intersection of 2 projected curves'}

FreeCADGui.addCommand('combined_projection', CombinedProjectionCmd())