import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino
import collections
import System


def MarkSurfaceDiscontinuities():

    types  = [Rhino.Geometry.Continuity.G1_continuous, Rhino.Geometry.Continuity.G2_continuous]
    
    while True:
        details= False
        if sc.sticky.has_key('DISCO_DETAILS'):
            details = sc.sticky['DISCO_DETAILS']
        
        samp =32
        if sc.sticky.has_key('DISCO_SAMPLES'):
            samp = sc.sticky['DISCO_SAMPLES']
            
            
        knotColor = System.Drawing.Color.White
        if sc.sticky.has_key('DISCO_KNOT_COLR'):
            knotColor = sc.sticky['DISCO_KNOT_COLR']
            
        g0Color = System.Drawing.Color.Red
        if sc.sticky.has_key('DISCO_G0Color'):
            g0Color = sc.sticky['DISCO_G0Color']
            
            
        g1Color = System.Drawing.Color.Magenta
        if sc.sticky.has_key('DISCO_G1Color'):
            g1Color = sc.sticky['DISCO_G1Color']
            
        MK = False
        if sc.sticky.has_key('DISCO_MARK_MK'):
            MK = sc.sticky['DISCO_MARK_MK']
            
        go = Rhino.Input.Custom.GetObject()
        go.GeometryFilter = Rhino.DocObjects.ObjectType.Surface
        
        opSample = Rhino.Input.Custom.OptionInteger(samp)
        
        opMK = Rhino.Input.Custom.OptionToggle(MK, "No", "Yes")
        
        opKnotColor = Rhino.Input.Custom.OptionColor(knotColor)
        opColor0 = Rhino.Input.Custom.OptionColor(g0Color)
        opColor1 = Rhino.Input.Custom.OptionColor(g1Color)
        opDetails = Rhino.Input.Custom.OptionToggle(details, "No", "Yes")

        go.AddOptionToggle("Details", opDetails)
        go.AddOptionToggle("MarkAllFullyMultipleKnots", opMK)
        go.AddOptionColor("KnotColor", opKnotColor)
        go.AddOptionColor("G0Color", opColor0)
        go.AddOptionColor("G1Color", opColor1)
        
        if details:
            go.AddOptionInteger("Samples", opSample)
            go.AcceptNumber(True, False)
        
        rc = go.Get()
        
        if go.CommandResult()!=Rhino.Commands.Result.Success:
            return go.CommandResult()
            
        if rc == Rhino.Input.GetResult.Object:
            obj = go.Object(0)
            id = obj.ObjectId
            break
        elif rc == Rhino.Input.GetResult.Number:
            samp = int(go.Number())
            if samp < 3:
                samp = sc.sticky['DISCO_SAMPLES']
                continue
            else:
                sc.sticky ['DISCO_SAMPLES'] = samp
                continue
                
        elif rc == Rhino.Input.GetResult.Option:
            idx = go.OptionIndex()
            
            if idx == 1:
                details = opDetails.CurrentValue
                sc.sticky ['DISCO_DETAILS'] = details
                continue
            elif idx == 2:
                MK = opMK.CurrentValue
                sc.sticky['DISCO_MARK_MK'] = MK
                continue
            elif idx == 3:
                knotColor= opKnotColor.CurrentValue
                sc.sticky['DISCO_KNOT_COLR'] = knotColor
                continue
                
            elif idx == 4:
                g0Color= opColor0.CurrentValue
                sc.sticky['DISCO_G0Color'] = g0Color
                continue
                
            elif idx == 5:
                g1Color = opColor1.CurrentValue
                sc.sticky['DISCO_G1Color'] = g1Color
                continue
                
            elif idx == 6:
                samp = opSample.CurrentValue
                sc.sticky['DISCO_SAMPLE'] = samp
                continue
                
    if not id: return
    
    brep = sc.doc.Objects.Find(id).Geometry
    
    if not isinstance(brep, Rhino.Geometry.Brep):
        brep = brep.ToBrep()
    
    srf = brep.Surfaces[0]

    if isinstance(srf, Rhino.Geometry.RevSurface) or isinstance(srf, Rhino.Geometry.SumSurface):
        srf = srf.ToNurbsSurface()
        
    degU = srf.Degree(0)
    degV = srf.Degree(1)
    
    domU = srf.Domain(0)
    domV = srf.Domain(1)
    
    
    kV = srf.KnotsV
    for p in range(kV.Count):
        print kV.KnotMultiplicity(p)
    
    
    kU = list(srf.KnotsU)
    kV = list(srf.KnotsV)
    

    
    multU = list(set([item for item in kU if kU.count(item) == degU and item != domU.Min and item != domU.Max]))
    multV = list(set([item for item in kV if kV.count(item) == degV and item != domV.Min and item != domV.Max]))
    
    markersU = []
    markersV = []
    
    if len(multU) >0: markersU = [srf.IsoCurve(1, item) for item in multU]
    if len(multV) >0: markersV = [srf.IsoCurve(0, item) for item in multV]
    
    usedCurves = []
    
    if multU:
        for n in range(len( markersU)):
            for i in range(len(types)):
                
                pars = markersU[n].DivideByCount(samp, True)
                if pars:
                    disco=0

                    if markersU[n] not in usedCurves:
                        max = (0,0)
                        for par in pars:
                            if not srf.IsContinuous(types[i], multU[n], par):
                                usedCurves.append(markersU[n])
                                disco= i+1
                                if details:
                                    tempIso = srf.IsoCurve(0, par)
                                    pt = tempIso.PointAt(multU[n])
                                    tempSplit = tempIso.Split(multU[n])
                                    
                                    if i == 0:
        
                                        tan1 = tempSplit[0].TangentAt(multU[n])
                                        tan2 = tempSplit[1].TangentAt(multU[n])
                                        tempMax = Rhino.RhinoMath.ToDegrees(Rhino.Geometry.Vector3d.VectorAngle(tan1,tan2))
                                        #print (tempMax, max)
                                        if tempMax > max[0]: max = (tempMax, pt)
        
                                    else:
                                        c1 = tempSplit[0].CurvatureAt(multU[n])
                                        if c1.IsTiny():
                                            c1 = 0
                                        else:
                                            c1= c1.Length
                                            
                                        c2 = tempSplit[1].CurvatureAt(multU[n])
                                        if c2.IsTiny():
                                            c2 = 0
                                        else:
                                            c2 = c2.Length
                                        tempMax = abs(c2-c1)
                                        
                                        #print tempMax
                                        if tempMax > max[0]: max = (tempMax, pt)
                                
                            
                    if i == 0:
                        color = g0Color
                    else:
                        color = g1Color
                            
                if disco > 0:
                    tempId = sc.doc.Objects.AddCurve(markersU[n])
                    rs.ObjectColor(tempId, color)                       
                    if details:
                        if disco == 1:
                            print "Not " + str(types[i]) + ". Maximum sampled angle " + str(round(max[0],3)) + chr(176)
                            rs.AddTextDot(str(round(max[0], 3))+chr(176), max[1])
                        else:
                            print "Not " + str(types[i]) + ". Maximum sampled curvature difference " + str(round(max[0],3))
                            rs.AddTextDot(str(round(max[0], 3)), max[1])
 
    if multV:
        for n in range(len( markersV)):

            for i in range(len(types)):
                pars = markersV[n].DivideByCount(samp, True)
                
                if pars:
                    disco=0
                    
                    if markersV[n] not in usedCurves:
                        max = (0,0)
                        for par in pars:
                            if not srf.IsContinuous(types[i], par, multV[n]):
                                usedCurves.append(markersV[n])
                                disco= i+1
                                if details:
                                    tempIso = srf.IsoCurve(1, par)
                                    pt = tempIso.PointAt(multV[n])
                                    tempSplit = tempIso.Split(multV[n])
                                    
                                    if i == 0:
                                        tan1 = tempSplit[0].TangentAt(multV[n])
                                        tan2 = tempSplit[1].TangentAt(multV[n])
                                        tempMax = Rhino.RhinoMath.ToDegrees(Rhino.Geometry.Vector3d.VectorAngle(tan1,tan2))
                                        #print (tempMax, max)
                                        if tempMax > max[0]: max = (tempMax, pt)
        
                                    else:
    
                                        c1 = tempSplit[0].CurvatureAt(multV[n])
                                        if c1.IsTiny():
                                            c1 = 0
                                        else:
                                            c1= c1.Length
                                            
                                        c2 = tempSplit[1].CurvatureAt(multV[n])
                                        if c2.IsTiny():
                                            c2 = 0
                                        else:
                                            c2 = c2.Length
                                        tempMax = abs(c2-c1)
                                        if tempMax > max[0]: max = (tempMax, pt)
                                    
                         
                            
                    if i == 0:
                        color = g0Color
                    else:
                        color = g1Color

                            
                if disco > 0:
                    tempId = sc.doc.Objects.AddCurve(markersV[n])
                    rs.ObjectColor(tempId, color)                       
                    if details:
                        if disco == 1:
                            print "Not " + str(types[i]) + ". Maximum sampled angle " + str(round(max[0],3)) + chr(176)
                            rs.AddTextDot(str(round(max[0], 3))+chr(176), max[1])
                        else:
                            print "Not " + str(types[i]) + ". Maximum sampled curvature difference " + str(round(max[0],3))
                            rs.AddTextDot(str(round(max[0], 3)), max[1])
            #break
    if MK:
        allCurves = markersV + markersU
        
        for item in allCurves:
            if item not in usedCurves:
                tempId = sc.doc.Objects.AddCurve(item)
                rs.ObjectColor(tempId, knotColor)
                
    sc.doc.Views.Redraw()

if __name__ == '__main__':MarkSurfaceDiscontinuities()