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

__title__="Macro IsoCurves"
__author__ = "Chris_G"
__doc__ = '''
Macro IsoCurves.
Creates a parametric isoCurve from a face

Instructions:
Select a face in the 3D View.
Then, in Py console:

import IsoCurves
IsoCurves.run()

'''

import FreeCAD as App
if App.GuiUp:
    import FreeCADGui as Gui
import Part
import isocurves
import _utils

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




def makeIsoCurveFeature():
    '''makeIsoCurveFeature(): makes a IsoCurve parametric feature object. Returns the new object.'''
    selfobj = App.ActiveDocument.addObject("Part::FeaturePython","IsoCurve")
    IsoCurve(selfobj)
    ViewProviderIsoCurve(selfobj.ViewObject)
    return selfobj

class IsoCurve:
    "The IsoCurve feature object"
    def __init__(self,selfobj):
        selfobj.addProperty("App::PropertyLinkSub","Face","IsoCurve","Input face")
        selfobj.addProperty("App::PropertyFloat","Parameter","IsoCurve","IsoCurve parameter").Parameter=0.
        selfobj.addProperty("App::PropertyInteger","NumberU","IsoCurve","Number of IsoCurve in U direction").NumberU=3
        selfobj.addProperty("App::PropertyInteger","NumberV","IsoCurve","Number of IsoCurve in V direction").NumberV=3
        selfobj.addProperty("App::PropertyEnumeration","Multi","IsoCurve","Number of IsoCurve").Multi=["Single","Multi"]
        selfobj.addProperty("App::PropertyEnumeration","Orientation","IsoCurve","Curve Orientation").Orientation=["U","V"]
        selfobj.Multi = "Single"
        selfobj.Proxy = self

    def split(self, e, t0, t1):
        p0,p1 = e.ParameterRange
        if (t0 > p0) & (t1 < p1):
            w = e.split([t0,t1])
            return w.Edges[1]
        elif (t0 > p0):
            w = e.split(t0)
            return w.Edges[1]
        elif (t1 < p1):
            w = e.split(t1)
            return w.Edges[0]
        else:
            return e

    def getBounds(self, obj):
        face = self.getFace(obj)
        self.u0, self.u1, self.v0, self.v1 = face.ParameterRange

    def getFace(self, obj):
        return _utils.getShape(obj, "Face", "Face")

    def tangentAt(self, selfobj, p):
        if selfobj.Orientation == 'U':
            if (p >= self.v0) & (p <= self.v1):
                return selfobj.Shape.tangentAt(p)
            else:
                App.Console.PrintError("Parameter out of range (%f, %f)\n"%(self.v0,self.v1))
        if selfobj.Orientation == 'V':
            if (p >= self.u0) & (p <= self.u1):
                return selfobj.Shape.tangentAt(p)
            else:
                App.Console.PrintError("Parameter out of range (%f, %f)\n"%(self.u0,self.u1))

    def normalAt(self, selfobj, p):
        face = self.getFace(selfobj)
        if selfobj.Orientation == 'U':
            if (p >= self.v0) & (p <= self.v1):
                return face.normalAt(selfobj.Parameter, p)
            else:
                App.Console.PrintError("Parameter out of range (%f, %f)\n"%(self.v0,self.v1))
        if selfobj.Orientation == 'V':
            if (p >= self.u0) & (p <= self.u1):
                return face.normalAt(p, selfobj.Parameter)
            else:
                App.Console.PrintError("Parameter out of range (%f, %f)\n"%(self.u0,self.u1))


    def execute(self,selfobj):

        face = self.getFace(selfobj)
        #u0,u1,v0,v1 = face.ParameterRange
        if face:
            if selfobj.Multi == 'Multi':
                w = isocurves.multiIso(face, selfobj.NumberU, selfobj.NumberV).toShape()
            else:
                if selfobj.Orientation == 'U':
                    ci = isocurves.multiIso(face, 1, 0)
                    ci.paramu = [selfobj.Parameter]
                    ci.computeU()
                else:
                    ci = isocurves.multiIso(face, 0, 1)
                    ci.paramv = [selfobj.Parameter]
                    ci.computeV()
                w = ci.toShape()
            selfobj.Shape = w
        else:
            return False

    def onChanged(self, selfobj, prop):
        if prop == 'Face':
            face = self.getFace(selfobj)
            self.getBounds(selfobj)
            if selfobj.Orientation == "U":
                self.p0 = self.u0
                self.p1 = self.u1
            else:
                self.p0 = self.v0
                self.p1 = self.v1
        if prop == 'Multi':
            if selfobj.Multi  == "Single":
                selfobj.setEditorMode("Parameter", 0)
                selfobj.setEditorMode("Orientation", 0)
                selfobj.setEditorMode("NumberU", 2)
                selfobj.setEditorMode("NumberV", 2)
            elif selfobj.Multi  == "Multi":
                selfobj.setEditorMode("Parameter", 2)
                selfobj.setEditorMode("Orientation", 2)
                selfobj.setEditorMode("NumberU", 0)
                selfobj.setEditorMode("NumberV", 0)
            selfobj.Proxy.execute(selfobj)
        if prop == 'Parameter':
            if  selfobj.Parameter  < self.p0:
                selfobj.Parameter  = self.p0
            elif selfobj.Parameter  > self.p1:
                selfobj.Parameter  = self.p1
            selfobj.Proxy.execute(selfobj)
        if prop == 'NumberU':
            if  selfobj.NumberU  < 1:
                selfobj.NumberU  = 1
            elif selfobj.NumberU  > 1000:
                selfobj.NumberU  = 1000
            selfobj.Proxy.execute(selfobj)
        if prop == 'NumberV':
            if  selfobj.NumberV  < 1:
                selfobj.NumberV  = 1
            elif selfobj.NumberV  > 1000:
                selfobj.NumberV  = 1000
            selfobj.Proxy.execute(selfobj)
        if prop == 'Orientation':
            self.getBounds(selfobj)
            if selfobj.Orientation == "U":
                self.p0 = self.u0
                self.p1 = self.u1
            else:
                self.p0 = self.v0
                self.p1 = self.v1
            selfobj.Proxy.execute(selfobj)

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

    def attach(self, vobj):
        self.ViewObject = vobj
        self.Object = vobj.Object
  
    def setEdit(self,vobj,mode):
        return False
    
    def unsetEdit(self,vobj,mode):
        return

    def __getstate__(self):
        return None

    def __setstate__(self,state):
        return None

    #def claimChildren(self):
        #return None #[self.Object.Base, self.Object.Tool]
        
    def onDelete(self, feature, subelements): # subelements is a tuple of strings
        #try:
            #self.Object.Base.ViewObject.show()
            #self.Object.Tool.ViewObject.show()
        #except Exception as err:
            #FreeCAD.Console.PrintError("Error in onDelete: {0} \n".format(err))
        return True

class CommandMacroIsoCurve:
    "Command to create IsoCurve feature"
    def GetResources(self):
        return {'Pixmap'  : TOOL_ICON,
                'MenuText': "IsoCurve",
                'Accel': "",
                'ToolTip': "IsoCurve: Create an IsoCurve from a face"}

    def Activated(self):
        run()
    def IsActive(self):
        if App.ActiveDocument:
            return True
        else:
            return False

if App.GuiUp:
    Gui.addCommand("IsoCurve", CommandMacroIsoCurve())

def run():
    sel = Gui.Selection.getSelectionEx()
    try:
        if len(sel) != 1:
            raise Exception("Select one face only.")
        try:
            App.ActiveDocument.openTransaction("Macro IsoCurve")
            selfobj = makeIsoCurveFeature()
            so = sel[0].SubObjects[0]
            p = sel[0].PickedPoints[0]
            poe = so.distToShape(Part.Vertex(p))
            par = poe[2][0][2]
            selfobj.Face = [sel[0].Object,sel[0].SubElementNames]
            selfobj.Parameter = par[0]
            selfobj.Proxy.execute(selfobj)
        finally:
            App.ActiveDocument.commitTransaction()
    except Exception as err:
        from PySide import QtGui
        mb = QtGui.QMessageBox()
        mb.setIcon(mb.Icon.Warning)
        mb.setText("{0}".format(err))
        mb.setWindowTitle("Macro IsoCurve")
        mb.exec_()