################################################################################
# attach.py
#
# NC code creator for attaching Z coordinates to a surface
#

import recreator
try:
    import ocl
    import ocl_funcs
except ImportError:
    import opencamlib as ocl
import nc

attached = False
units = 1.0

################################################################################
class Creator(recreator.Redirector):

    def __init__(self, original):
        recreator.Redirector.__init__(self, original)

        self.stl = None
        self.cutter = None
        self.minz = None
        self.path = None
        self.pdcf = None
        self.material_allowance = 0.0

    ############################################################################
    ##  Shift in Z

    def setPdcfIfNotSet(self):
        if self.pdcf == None:
            self.pdcf = ocl.PathDropCutter()
            self.pdcf.setSTL(self.stl)
            self.pdcf.setCutter(self.cutter)
            self.pdcf.setSampling(0.1)
            self.pdcf.setZ(self.minz/units)

    def z2(self, z):
        path = ocl.Path()
        # use a line with no length
        path.append(ocl.Line(ocl.Point(self.x, self.y, self.z), ocl.Point(self.x, self.y, self.z)))
        self.setPdcfIfNotSet()
        if (self.z>self.minz):
            self.pdcf.setZ(self.z)  # Adjust Z if we have gotten a higher limit (Fix pocketing loosing steps when using attach?)
        else:
            self.pdcf.setZ(self.minz/units) # Else use minz
        self.pdcf.setPath(path)
        self.pdcf.run()
        plist = self.pdcf.getCLPoints()
        p = plist[0]
        return p.z + self.material_allowance/units

    def cut_path(self):
        if self.path == None: return
        self.setPdcfIfNotSet()

        if (self.z>self.minz):
            self.pdcf.setZ(self.z)  # Adjust Z if we have gotten a higher limit (Fix pocketing loosing steps when using attach?)
        else:
            self.pdcf.setZ(self.minz/units) # Else use minz

       # get the points on the surface
        self.pdcf.setPath(self.path)

        self.pdcf.run()
        plist = self.pdcf.getCLPoints()

        #refine the points
        f = ocl.LineCLFilter()
        f.setTolerance(0.005)
        for p in plist:
            f.addCLPoint(p)
        f.run()
        plist = f.getCLPoints()

        i = 0
        for p in plist:
            if i > 0:
                self.original.feed(p.x/units, p.y/units, p.z/units + self.material_allowance/units)
            i = i + 1

        self.path = ocl.Path()

    def rapid(self, x=None, y=None, z=None, a=None, b=None, c=None ):
        if z != None:
            if z < self.z:
                return
        recreator.Redirector.rapid(self, x, y, z, a, b, c)

    def feed(self, x=None, y=None, z=None, a=None, b=None, c=None):
        px = self.x
        py = self.y
        pz = self.z
        recreator.Redirector.feed(self, x, y, z, a, b, c)
        if self.x == None or self.y == None or self.z == None:
            return
        if px == self.x and py == self.y:
            return

        # add a line to the path
        if self.path == None: self.path = ocl.Path()
        self.path.append(ocl.Line(ocl.Point(px, py, pz), ocl.Point(self.x, self.y, self.z)))

    def arc(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None, ccw = True):
        px = self.x
        py = self.y
        pz = self.z
        recreator.Redirector.arc(self, x, y, z, i, j, k, r, ccw)

        # add an arc to the path
        if self.path == None: self.path = ocl.Path()
        self.path.append(ocl.Arc(ocl.Point(px, py, pz), ocl.Point(self.x, self.y, self.z), ocl.Point(i, j, pz), ccw))

    def set_ocl_cutter(self, cutter):
        self.cutter = cutter

################################################################################

def attach_begin():
    global attached
    if attached == True:
        attach_end()
    nc.creator = Creator(nc.creator)
    recreator.units = units
    attached = True
    nc.creator.pdcf = None
    nc.creator.path = None

def attach_end():
    global attached
    nc.creator.cut_path()
    nc.creator = nc.creator.original
    attached = False
