Esempio n. 1
0
		def appendCross(block):
			block.append("m5")
			block.append(CNC.grapid(x=x0, y=y0 + marksizehalf, f=movefeed))
			block.append(self.getPowerLine(app))
			block.append(CNC.gline(y=y0 - marksizehalf, f=drawfeed))
			block.append("m5")
			block.append(CNC.grapid(x=x0 + marksizehalf, y=y0, f=movefeed))
			block.append(self.getPowerLine(app))
			block.append(CNC.gline(x=x0 - marksizehalf, f=drawfeed))
			block.append("m5")
Esempio n. 2
0
 def appendCross(block):
     block.append("m5")
     block.append(CNC.grapid(x=x0, y=y0 + marksizehalf, f=movefeed))
     block.append(self.getPowerLine(app))
     block.append(CNC.gline(y=y0 - marksizehalf, f=drawfeed))
     block.append("m5")
     block.append(CNC.grapid(x=x0 + marksizehalf, y=y0, f=movefeed))
     block.append(self.getPowerLine(app))
     block.append(CNC.gline(x=x0 - marksizehalf, f=drawfeed))
     block.append("m5")
Esempio n. 3
0
    def generate(self,
                 board_width,
                 board_height,
                 number_of_pieces,
                 random_seed=0,
                 tap_shape='basic',
                 threshold=3.0):
        blocks = []
        block = Block(self.name)
        random.seed(random_seed)
        Arc.reset_used_arcs()
        Arc.set_diff_threshold(threshold)
        puzzle_cuts = self.__class__.make_puzzle_cuts(board_width,
                                                      board_height,
                                                      number_of_pieces,
                                                      tap_shape, threshold)

        # Draw puzzle cuts
        x = 0
        y = 0
        for i in range(0, int(self.thickness / self.step_z)):
            for cut in puzzle_cuts:
                block.append(CNC.zsafe())
                block.append(CNC.grapid(x + cut[0].x, y + cut[0].y))
                block.append(CNC.zenter(0.0))
                block.append(CNC.fmt("f", self.cut_feed))
                block.append(CNC.zenter(-(i + 1) * self.step_z))
                for arc in cut:
                    if arc.r:
                        block.append(
                            CNC.garc(arc.direction,
                                     x + arc.x,
                                     y + arc.y,
                                     r=arc.r))

        blocks.append(block)

        # Draw border
        block = Block(self.name + "_border")

        block.append(CNC.zsafe())
        block.append(CNC.grapid(x, y))

        for i in range(0, int(self.thickness / self.step_z)):
            block.append(CNC.fmt("f", self.cut_feed))
            block.append(CNC.zenter(-(i + 1) * self.step_z))
            block.append(CNC.gline(x + board_width, y))
            block.append(CNC.gline(x + board_width, y + board_height))
            block.append(CNC.gline(x, y + board_height))
            block.append(CNC.gline(x, y))

        block.append(CNC.zsafe())
        blocks.append(block)

        return blocks
Esempio n. 4
0
 def appendCross45(block):
     msh = marksizehalf * self.sin45
     block.append("m5")
     block.append(CNC.grapid(x=x0 - msh, y=y0 + msh, f=movefeed))
     block.append(self.getPowerLine(app))
     block.append(CNC.gline(x=x0 + msh, y=y0 - msh, f=drawfeed))
     block.append("m5")
     block.append(CNC.grapid(x=x0 + msh, y=y0 + msh, f=movefeed))
     block.append(self.getPowerLine(app))
     block.append(CNC.gline(x=x0 - msh, y=y0 - msh, f=drawfeed))
     block.append("m5")
Esempio n. 5
0
		def appendCross45(block):
			msh = marksizehalf * self.sin45
			block.append("m5")
			block.append(CNC.grapid(x=x0 - msh, y=y0 + msh, f=movefeed))
			block.append(self.getPowerLine(app))
			block.append(CNC.gline(x=x0 + msh, y=y0 - msh, f=drawfeed))
			block.append("m5")
			block.append(CNC.grapid(x=x0 + msh, y=y0 + msh, f=movefeed))
			block.append(self.getPowerLine(app))
			block.append(CNC.gline(x=x0 - msh, y=y0 - msh, f=drawfeed))
			block.append("m5")
Esempio n. 6
0
	def make(self, Nlines, LineLen, StartEndLen, Step, CornerRes, Depth):

		blocks = []
		block = Block(self.name)

		points = self.zigzag(Nlines, LineLen, StartEndLen, Step, CornerRes)

		block.append(CNC.zsafe())
		block.append(CNC.grapid(points[0][0],points[0][1]))

		currDepth = 0.
		stepz = CNC.vars['stepz']
		if stepz==0 : stepz=0.001  #avoid infinite while loop

		while True:
			currDepth -= stepz
			if currDepth < Depth : currDepth = Depth
			block.append(CNC.zenter(currDepth))
			block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])]))
			for (x,y) in points:
				block.append(CNC.gline(x,y))
			if currDepth <= Depth : break

		block.append(CNC.zsafe())
		blocks.append(block)
		return blocks
Esempio n. 7
0
    def make(self, n=2, size=100, depth=0):
        self.n = n
        self.size = size
        self.depth = depth

        blocks = []
        block = Block(self.name)

        xi, yi = zip(*(self.hilbert(0.0, 0.0, size, 0.0, 0.0, size, n)))

        block.append(CNC.zsafe())
        block.append(CNC.grapid(xi[0], yi[0]))

        currDepth = 0.
        stepz = CNC.vars['stepz']
        if stepz == 0: stepz = 0.001  #avoid infinite while loop

        while True:
            currDepth -= stepz
            if currDepth < self.depth: currDepth = self.depth
            block.append(CNC.zenter(currDepth))
            block.append(CNC.gcode(1, [("f", CNC.vars["cutfeed"])]))
            for x, y in zip(xi, yi):
                block.append(CNC.gline(x, y))
            if currDepth <= self.depth: break

        block.append(CNC.zsafe())
        blocks.append(block)
        return blocks
Esempio n. 8
0
	def make(self, Nlines, LineLen, StartEndLen, Step, CornerRes, Depth):
		blocks = []
		block = Block(self.name)

		points = self.zigzag(Nlines, LineLen, StartEndLen, Step, CornerRes)

		block.append(CNC.zsafe())
		block.append(CNC.grapid(points[0][0],points[0][1]))

		currDepth = 0.
		stepz = CNC.vars['stepz']
		if stepz==0 : stepz=0.001  #avoid infinite while loop

		while True:
			currDepth -= stepz
			if currDepth < Depth : currDepth = Depth
			block.append(CNC.zenter(currDepth))
			block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])]))
			for (x,y) in points:
				block.append(CNC.gline(x,y))
			if currDepth <= Depth : break

		block.append(CNC.zsafe())
		blocks.append(block)
		return blocks
Esempio n. 9
0
	def calc(self,x,y,depth,peck,dwell,drillFeed,safeZforG0):
		self.safeZforG0 =float(abs(safeZforG0))
		peck=abs(float(peck))
		currentz=0.0
		self.blocks = []
		self.block = Block(self.name)
		self.block.append(CNC.grapid(x=x,y=y))
		self.block.append(CNC.grapid(z=CNC.vars["safe"]))
		self.accelerateIfNeeded(0.0,drillFeed)
		self.block.append("(entered)")
		while(currentz>depth):
			currentz-=peck
			if currentz < depth:
				currentz = depth
			kwargs={"f":float(drillFeed)}
			self.block.append(CNC.gline(None,None,float(currentz),**kwargs))
			if self.safeZforG0 >0:
				self.block.append(CNC.grapid(z=0.0+self.safeZforG0))
			else :
				self.block.append(CNC.grapid(z=CNC.vars["safe"]))
			self.block.append("g4 %s"%(CNC.fmt("p",float(dwell))))
			if currentz > depth:
				self.accelerateIfNeeded(currentz,drillFeed)
		self.block.append("(exiting)")
		self.block.append(CNC.grapid(z=CNC.vars["safe"]))
		self.blocks.append(self.block)
		return self.blocks
Esempio n. 10
0
	def make(self,n = 2, size = 100, depth = 0):
		self.n = n
		self.size = size
		self.depth = depth

		blocks = []
		block = Block(self.name)

		xi,yi = zip(*(self.hilbert(0.0,0.0,size,0.0,0.0,size,n)))

		block.append(CNC.zsafe())
		block.append(CNC.grapid(xi[0],yi[0]))

		currDepth = 0.
		stepz = CNC.vars['stepz']
		if stepz==0 : stepz=0.001  #avoid infinite while loop

		while True:
			currDepth -= stepz
			if currDepth < self.depth : currDepth = self.depth
			block.append(CNC.zenter(currDepth))
			block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])]))
			for x,y in zip(xi,yi):
				block.append(CNC.gline(x,y))
			if currDepth <= self.depth : break

		block.append(CNC.zsafe())
		blocks.append(block)
		return blocks
Esempio n. 11
0
		def appendSpikes(block):
			sinSpike = math.sin(math.atan(2.0 - math.sqrt(3)))
			cosSpike = math.cos(math.atan(2.0 - math.sqrt(3)))
			block.append("m5")
			block.append(CNC.grapid(x=x0, y=y0, f=movefeed))
			block.append(self.getPowerLine(app))
			block.append(CNC.gline(x=x0 + marksizehalf * sinSpike, y=y0 - marksizehalf * cosSpike, f=drawfeed))
			block.append(CNC.gline(x=x0 - marksizehalf * sinSpike, y=y0 - marksizehalf * cosSpike, f=drawfeed))
			block.append(CNC.gline(x=x0 + marksizehalf * sinSpike, y=y0 + marksizehalf * cosSpike, f=drawfeed))
			block.append(CNC.gline(x=x0 - marksizehalf * sinSpike, y=y0 + marksizehalf * cosSpike, f=drawfeed))
			block.append(CNC.gline(x=x0, y=y0, f=drawfeed))
			block.append(CNC.gline(x=x0 - marksizehalf * cosSpike, y=y0 + marksizehalf * sinSpike, f=drawfeed))
			block.append(CNC.gline(x=x0 - marksizehalf * cosSpike, y=y0 - marksizehalf * sinSpike, f=drawfeed))
			block.append(CNC.gline(x=x0 + marksizehalf * cosSpike, y=y0 + marksizehalf * sinSpike, f=drawfeed))
			block.append(CNC.gline(x=x0 + marksizehalf * cosSpike, y=y0 - marksizehalf * sinSpike, f=drawfeed))
			block.append(CNC.gline(x=x0, y=y0, f=drawfeed))
			block.append("m5")
Esempio n. 12
0
    def make(self, RExt=50.0, RInt=33.0, ROff=13.0, Depth=0):
        self.RExt = RExt
        self.RInt = RInt
        self.ROff = ROff

        if RExt > RInt:
            self.Spins = self.lcm(RExt, RInt) / max(RExt, RInt)
        else:
            self.Spins = self.lcm(RExt, RInt) / min(RExt, RInt)

        self.Depth = Depth
        self.PI = math.pi
        self.theta = 0.0

        blocks = []
        block = Block(self.name)

        block.append("(External Radius = %g)" % (self.RExt))
        block.append("(Internal Radius = %g)" % (self.RInt))
        block.append("(Offset Radius = %g)" % (self.ROff))

        xi, yi = zip(*(self.calc_dots()))

        block.append(CNC.zsafe())
        block.append(CNC.grapid(xi[0], yi[0]))

        currDepth = 0.0
        stepz = CNC.vars["stepz"]
        if stepz == 0:
            stepz = 0.001  # avoid infinite while loop

        while True:
            currDepth -= stepz
            if currDepth < self.Depth:
                currDepth = self.Depth
            block.append(CNC.zenter(currDepth))
            block.append(CNC.gcode(1, [("f", CNC.vars["cutfeed"])]))
            for x, y in zip(xi, yi):
                block.append(CNC.gline(x, y))
            block.append(CNC.gline(xi[0], yi[0]))
            if currDepth <= self.Depth:
                break

        block.append(CNC.zsafe())
        blocks.append(block)
        return blocks
Esempio n. 13
0
		def addSingleCircle(radius, depth):
			if pocket:
				block.append(CNC.grapid(0., 0.))
				block.append(CNC.zenter(depth))
				setCutFeedrate()
				currRadius = 0.
				while radius > currRadius+stepxy:
					currRadius += stepxy
					block.append(CNC.gline(currRadius, 0))
					addCircumference(currRadius)
				if radius-currRadius > 0:
					block.append(CNC.gline(radius, 0))
					addCircumference(radius)
			else:
				block.append(CNC.grapid(radius, 0.))
				block.append(CNC.zenter(depth))
				setCutFeedrate()
				addCircumference(radius)
Esempio n. 14
0
File: bowl.py Progetto: asm7100/bCNC
		def addSingleCircle(radius, depth):
			if pocket:
				block.append(CNC.grapid(0., 0.))
				block.append(CNC.zenter(depth))
				setCutFeedrate()
				currRadius = 0.
				while radius > currRadius+stepxy:
					currRadius += stepxy
					block.append(CNC.gline(currRadius, 0))
					addCircumference(currRadius)
				if radius-currRadius > 0:
					block.append(CNC.gline(radius, 0))
					addCircumference(radius)
			else:
				block.append(CNC.grapid(radius, 0.))
				block.append(CNC.zenter(depth))
				setCutFeedrate()
				addCircumference(radius)
Esempio n. 15
0
    def create_block(self, holes, name):
        targetDepth = self.fromMm("TargetDepth")
        peck = self.fromMm("Peck")
        dwell = self["Dwell"]
        block = Block(name)
        holesCount = 0

        if self.useCustom:
            block.append("M3 S0")
        else:
            block.append(CNC.zsafe())

        for bid in holes:
            for xH, yH, zH in bid:
                holesCount += 1

                if self.useCustom:
                    block.append(
                        CNC.grapid(x=xH, y=yH) + CNC.fmt(' F', self.rFeed))
                else:
                    #block.append(CNC.zsafe()) # Moved up
                    block.append(CNC.grapid(xH, yH))

                if peck != 0:
                    z = 0
                    while z > targetDepth:
                        z = max(z - peck, targetDepth)
                        if self.useCustom:
                            block.append(
                                "( --- WARNING! Peck is not setup for laser mode --- )"
                            )
                            break
                        else:
                            block.append(CNC.zenter(zH + z))
                            block.append(CNC.zsafe())

                if self.useCustom:
                    block.append("G1 S%s" % (self.spinMax))
                    block.append(CNC.gline(x=xH, y=yH))
                else:
                    block.append(CNC.zenter(zH + targetDepth))

                # Dwell time only on last pass
                if dwell != 0:
                    block.append(CNC.gcode(4, [("P", dwell)]))

                if self.useCustom:
                    block.append("G1 S%s" % (self.spinMin))
                else:
                    block.append(CNC.zsafe())

        # Gcode Zsafe on finish
        if self.useCustom:
            block.append("M5")
        else:
            block.append(CNC.zsafe())
        return (block, holesCount)
Esempio n. 16
0
    def calc(self, xstart, ystart, xend, yend, radius, cw):
        self.Points = []
        self.corners = [
            min(float(xstart), float(xend)),
            min(float(ystart), float(yend)),
            max(float(xstart), float(xend)),
            max(float(ystart), float(yend)),
        ]

        xmin, ymin, xmax, ymax = self.corners[0], self.corners[
            1], self.corners[2], self.corners[3]
        r = min(radius, (xmax - xmin) / 2, (ymax - ymin) / 2)
        blocks = []
        block = Block(self.name)
        block.append(CNC.grapid(x=xmin, y=ymin + r))
        block.append(CNC.grapid(z=0.0))
        block.append("(entered)")
        if cw:
            block.append(CNC.gline(x=xmin, y=ymax - r))
            if r > 0:
                block.append(CNC.garc(2, x=xmin + r, y=ymax, i=r, j=0))
            if (xmax - xmin) > 2 * r:
                block.append(CNC.gline(x=xmax - r, y=ymax))
            if r > 0:
                block.append(CNC.garc(2, x=xmax, y=ymax - r, i=0, j=-r))
            if (ymax - ymin) > 2 * r:
                block.append(CNC.gline(x=xmax, y=ymin + r))
            if r > 0:
                block.append(CNC.garc(2, x=xmax - r, y=ymin, i=-r, j=0))
            if (xmax - xmin) > 2 * r:
                block.append(CNC.gline(x=xmin + r, y=ymin))
            if r > 0:
                block.append(CNC.garc(2, x=xmin, y=ymin + r, i=0, j=r))
        else:
            if r > 0:
                block.append(CNC.garc(3, x=xmin + r, y=ymin, i=r, j=0))
            if (xmax - xmin) > 2 * r:
                block.append(CNC.gline(x=xmax - r, y=ymin))
            if r > 0:
                block.append(CNC.garc(3, x=xmax, y=ymin + r, i=0, j=r))
            if (ymax - ymin) > 2 * r:
                block.append(CNC.gline(x=xmax, y=ymax - r))
            if r > 0:
                block.append(CNC.garc(3, x=xmax - r, y=ymax, i=-r, j=0))
            if (xmax - xmin) > 2 * r:
                block.append(CNC.gline(x=xmin + r, y=ymax))
            if r > 0:
                block.append(CNC.garc(3, x=xmin, y=ymax - r, i=0, j=-r))
            if (ymax - ymin) > 2 * r:
                block.append(CNC.gline(x=xmin, y=ymin + r))
        block.append("(exiting)")
        block.append(CNC.grapid(z=CNC.vars["safe"]))
        blocks.append(block)
        return blocks
Esempio n. 17
0
	def generate(self, board_width, board_height, number_of_pieces, random_seed = 0, tap_shape = 'basic', threshold = 3.0):
		blocks = []
		block = Block(self.name)
		random.seed(random_seed)
		Arc.reset_used_arcs()
		Arc.set_diff_threshold(threshold)
		puzzle_cuts = self.__class__.make_puzzle_cuts(board_width, board_height, number_of_pieces, tap_shape, threshold)

		
		# Draw puzzle cuts
		x = 0
		y = 0
		for i in range(0, int(self.thickness / self.step_z)):
			for cut in puzzle_cuts:
				block.append(CNC.zsafe())
				block.append(CNC.grapid(x + cut[0].x, y + cut[0].y))
				block.append(CNC.zenter(0.0))
				block.append(CNC.fmt("f", self.cut_feed))
				block.append(CNC.zenter(-(i + 1) * self.step_z))
				for arc in cut:
					if arc.r:
						block.append(CNC.garc(arc.direction, x + arc.x, y + arc.y, r=arc.r))

		blocks.append(block)

		# Draw border
		block = Block(self.name + "_border")

		block.append(CNC.zsafe())
		block.append(CNC.grapid(x, y))

		for i in range(0, int(self.thickness / self.step_z)):
			block.append(CNC.fmt("f",self.cut_feed))
			block.append(CNC.zenter(-(i + 1) * self.step_z))
			block.append(CNC.gline(x + board_width, y))
			block.append(CNC.gline(x + board_width, y + board_height))
			block.append(CNC.gline(x, y + board_height))
			block.append(CNC.gline(x, y))

		block.append(CNC.zsafe())
		blocks.append(block)

		return blocks
Esempio n. 18
0
    def make(self, RExt=50., RInt=33., ROff=13., Depth=0):
        self.RExt = RExt
        self.RInt = RInt
        self.ROff = ROff

        if RExt > RInt:
            self.Spins = self.lcm(RExt, RInt) / max(RExt, RInt)
        else:
            self.Spins = self.lcm(RExt, RInt) / min(RExt, RInt)

        self.Depth = Depth
        self.PI = math.pi
        self.theta = 0.0

        blocks = []
        block = Block(self.name)

        block.append("(External Radius = %g)" % (self.RExt))
        block.append("(Internal Radius = %g)" % (self.RInt))
        block.append("(Offset Radius = %g)" % (self.ROff))

        xi, yi = zip(*(self.calc_dots()))

        block.append(CNC.zsafe())
        block.append(CNC.grapid(xi[0], yi[0]))

        currDepth = 0.
        stepz = CNC.vars['stepz']
        if stepz == 0: stepz = 0.001  #avoid infinite while loop

        while True:
            currDepth -= stepz
            if currDepth < self.Depth: currDepth = self.Depth
            block.append(CNC.zenter(currDepth))
            block.append(CNC.gcode(1, [("f", CNC.vars["cutfeed"])]))
            for x, y in zip(xi, yi):
                block.append(CNC.gline(x, y))
            block.append(CNC.gline(xi[0], yi[0]))
            if currDepth <= self.Depth: break

        block.append(CNC.zsafe())
        blocks.append(block)
        return blocks
Esempio n. 19
0
 def appendSpikes(block):
     sinSpike = math.sin(math.atan(2.0 - math.sqrt(3)))
     cosSpike = math.cos(math.atan(2.0 - math.sqrt(3)))
     block.append("m5")
     block.append(CNC.grapid(x=x0, y=y0, f=movefeed))
     block.append(self.getPowerLine(app))
     block.append(
         CNC.gline(x=x0 + marksizehalf * sinSpike,
                   y=y0 - marksizehalf * cosSpike,
                   f=drawfeed))
     block.append(
         CNC.gline(x=x0 - marksizehalf * sinSpike,
                   y=y0 - marksizehalf * cosSpike,
                   f=drawfeed))
     block.append(
         CNC.gline(x=x0 + marksizehalf * sinSpike,
                   y=y0 + marksizehalf * cosSpike,
                   f=drawfeed))
     block.append(
         CNC.gline(x=x0 - marksizehalf * sinSpike,
                   y=y0 + marksizehalf * cosSpike,
                   f=drawfeed))
     block.append(CNC.gline(x=x0, y=y0, f=drawfeed))
     block.append(
         CNC.gline(x=x0 - marksizehalf * cosSpike,
                   y=y0 + marksizehalf * sinSpike,
                   f=drawfeed))
     block.append(
         CNC.gline(x=x0 - marksizehalf * cosSpike,
                   y=y0 - marksizehalf * sinSpike,
                   f=drawfeed))
     block.append(
         CNC.gline(x=x0 + marksizehalf * cosSpike,
                   y=y0 + marksizehalf * sinSpike,
                   f=drawfeed))
     block.append(
         CNC.gline(x=x0 + marksizehalf * cosSpike,
                   y=y0 - marksizehalf * sinSpike,
                   f=drawfeed))
     block.append(CNC.gline(x=x0, y=y0, f=drawfeed))
     block.append("m5")
Esempio n. 20
0
	def writeGlyphContour(self,block,font,contours,fontSize,depth,xO, yO):
		width = font.header.x_max - font.header.x_min
		height = font.header.y_max - font.header.y_min
		scale = fontSize / font.header.units_per_em
		xO = xO * fontSize
		yO = yO * fontSize
		for cont in contours:
			block.append(CNC.zsafe())
			block.append(CNC.grapid(xO + cont[0].x * scale , yO + cont[0].y * scale))
			block.append(CNC.zenter(depth))
			block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])]))
			for p in cont:
				block.append(CNC.gline(xO + p.x * scale, yO + p.y * scale))
Esempio n. 21
0
	def writeGlyphContour(self,block,font,contours,fontSize,depth,xO, yO):
		width = font.header.x_max - font.header.x_min
		height = font.header.y_max - font.header.y_min
		scale = fontSize / font.header.units_per_em
		xO = xO * fontSize
		yO = yO * fontSize
		for cont in contours:
			block.append(CNC.zsafe())
			block.append(CNC.grapid(xO + cont[0].x * scale , yO + cont[0].y * scale))
			block.append(CNC.zenter(depth))
			block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])]))
			for p in cont:
				block.append(CNC.gline(xO + p.x * scale, yO + p.y * scale))
Esempio n. 22
0
 def calc(self, xstart, ystart, xend, yend):
     points = []
     points.append(Vector(xstart, ystart))
     points.append(Vector(xend, yend))
     first = points[0]
     last = points[1]
     blocks = []
     block = Block(self.name)
     block.append(CNC.grapid(first.x(), first.y()))
     block.append(CNC.grapid(z=0.0))
     block.append("(entered)")
     block.append(CNC.gline(last.x(), last.y()))
     block.append("(exiting)")
     block.append(CNC.grapid(z=CNC.vars["safe"]))
     blocks.append(block)
     return blocks
Esempio n. 23
0
	def accelerateIfNeeded(self,ztogo,drillfeed):
		if self.safeZforG0>0:
			self.block.append(CNC.grapid(z=ztogo+self.safeZforG0))
			kwargs={"f":float(drillfeed)}
			self.block.append(CNC.gline(None,None,ztogo,**kwargs))
Esempio n. 24
0
class GCode(object):
    """Gcode file"""
    LOOP_MERGE = False

    def __init__(self):
        self.cnc = CNC()
        self.undoredo = undo.UndoRedo()
        self.probe = Probe.Probe()
        self.orient = Orient()
        self.vars = {}  # local variables
        self.init()

    def init(self):
        """Reusable part of GCode initialisation"""
        self.filename = ""
        self.header = ""
        self.footer = ""

        OCV.blocks = []  # list of blocks
        # dummy values for min_z and max_z to correctly test when setted
        OCV.max_z = -9999
        OCV.min_z = 10000
        # TODO: maybe this could be used to name the blocks ?
        OCV.gcp_mop_name = ""
        #
        OCV.gcodelines = ["(-)",]  # Add a starting 0 pos to better align index
        self.vars.clear()
        self.undoredo.reset()
        # FIXME check if this is needed
        # self.probe.init()

        self._lastModified = 0
        self._modified = False

    def calculateEnableMargins(self):
        """Recalculate enabled path margins"""
        self.cnc.resetEnableMargins()
        for block in OCV.blocks:
            if block.enable:
                OCV.CD["xmin"] = min(OCV.CD["xmin"], block.xmin)
                OCV.CD["ymin"] = min(OCV.CD["ymin"], block.ymin)
                OCV.CD["zmin"] = min(OCV.CD["zmin"], block.zmin)
                OCV.CD["xmax"] = max(OCV.CD["xmax"], block.xmax)
                OCV.CD["ymax"] = max(OCV.CD["ymax"], block.ymax)
                OCV.CD["zmax"] = max(OCV.CD["zmax"], block.zmax)

    def isModified(self):
        """return internal _modifiedvalue"""
        return self._modified

    def resetModified(self):
        """reset internal _modified"""
        self._modified = False

    def __getitem__(self, item):
        """get block item"""
        return OCV.blocks[item]

    def __setitem__(self, item, value):
        """set block item"""
        OCV.blocks[item] = value

    def evaluate(self, line, app=None):
        """Evaluate code expressions if any and return line"""
        if isinstance(line, int):
            return None

        elif isinstance(line, list):
            for i, expr in enumerate(line):

                if isinstance(expr, types.CodeType):
                    result = eval(expr, OCV.CD, self.vars)

                    if isinstance(result, float):
                        line[i] = str(round(result, OCV.digits))
                    else:
                        line[i] = str(result)
            return "".join(line)

        elif isinstance(line, types.CodeType):
            # import traceback
            # traceback.print_stack()
            v = self.vars
            v['os'] = os
            v['app'] = app
            return eval(line, OCV.CD, self.vars)

        else:
            return line

    def parse_gcode(self, filename, adv_heur=False):
        """scan lines from gcodelines and parse them to create
        a proper OCV.blocks structure
        """

        if OCV.DEBUG_PAR is True:
            OCV.printout_header("Scanning {0}", filename)

        # preprocess file to find a Post processor marker
        prcs = True
        l_idx = 1
        l_bound = min(10, len(OCV.gcodelines))
        while prcs is True:
            line = OCV.gcodelines[l_idx]

            if line.startswith("( ver: okk-"):
                OCV.g_code_pp = "CamBam-OKK"
            else:
                pass

            if l_idx < (l_bound - 1):
                l_idx += 1
            else:
                prcs = False

        # act depending on prostprocessor marker
        # for now only 'CamBam-OKK' is implemented, using 'custom' grbl.cbpp
        # file as postprocessor in CamBam
        # others could be implemented if relevant information are supplied
        if OCV.g_code_pp in ("CamBam-OKK",):
            self.pre_process_gcode()
        else:
            # Plain Gcode file or not implemented "generators" are processed
            # using "add_line" method, in this case the g_code_pp value is
            # left 'Generic' as set in OCV file
            for line in OCV.gcodelines:
                self.add_line(line)

        Heuristic.trim_blocks()

        if OCV.DEBUG_PAR is True:
            OCV.printout_header("{0}", "END SCAN")

    def debug_info(self, line, move, move_s, move_f, delta_z):

        print(line)

        if (move_s[0], move_s[1]) != (move_f[0], move_f[1]):
            print("Motion {} Move start = {} \nMove end = {}".format(
                    move, move_s, move_f))
            print("Delta Z = ", delta_z)
        else:
            if delta_z > 0:
                print("Z_UP Move from {} to {} at X{} Y{}".format(
                        move_s[2], move_f[2], move_s[0], move_s[1]))
                print("Delta Z = {}".format(delta_z))
            elif delta_z < 0:
                print("Z_DOWN Move from {} to {} at X{} Y{}".format(
                        move_s[2], move_f[2], move_s[0], move_s[1]))
                print("Delta Z = {}".format(delta_z))
            else:
                print("Stationary Move at Point {}".format(move_s))

        print(OCV.str_sep)

    def pre_process_gcode(self):
        """scan gcode lines and inject some metadata, it create only one Block.
        The main scope is to populate OCV.blocks_ev list used in later
        elaboration done by Heuristic.process_blocks().
        See the Documentation in Heuristic.process_blocks() for more info.
        """
        # DEBUG_INFO activation only for this method
        INT_DEBUG = False
        OCV.infos = []

        process = True
        l_idx = -1
        OCV.blocks_ev = ["",]

        while process is True:
            if l_idx < (len(OCV.gcodelines) - 1):
                l_idx += 1
            else:
                # continue here is to force the loop to terminate here
                # if not present last line is scanned again
                process = False
                continue

            line = OCV.gcodelines[l_idx]

            if INT_DEBUG is True:
                print("{0} Line > {1}".format(l_idx, line))

                if l_idx == (len(OCV.gcodelines) - 1):
                    print("last line fo gcode")

            # discard the dummy first item
            if line.startswith("(-)"):
                continue

            if not OCV.blocks:
                OCV.blocks.append(Block("Header"))

            # events are processes later

            if line[:10] == "(MOP Start":
                OCV.blocks_ev.append(
                    ("MS", l_idx, line,
                     ((self.cnc.x, self.cnc.y, self.cnc.z),
                      self.cnc.zval,
                      (self.cnc.dx, self.cnc.dy, self.cnc.dz))))
                OCV.blocks[-1].append(line)
                continue

            if line[:8] == "(MOP End":
                # if there is a MOP end
                OCV.blocks_ev.append(
                    ("ME", l_idx, line,
                     ((self.cnc.x, self.cnc.y, self.cnc.z),
                      self.cnc.zval,
                      (self.cnc.dx, self.cnc.dy, self.cnc.dz))))
                OCV.blocks[-1].append(line)
                continue

            cmds = Heuristic.parse_line(line)
            # Debug infos do not delete
            # print(cmds)

            if cmds is None:
                # the line contains comments or no valid commands
                OCV.blocks[-1].append(line)
                continue

            # self.cnc.motionStart(cmds), analyze the move and populate the
            # positions, but the action is ended by sel.cnc.motionEnd(cmds)
            # in some condition the self.cnc.x(yz) variables hold a different
            # value at the start and at the end of operation, theese values
            # are both significative for the event, so this block of code
            # take care to "generate" the start value and the end value for
            # each line

            self.cnc.motionStart(cmds)
            move = cmds[0]
            move_s = (self.cnc.x, self.cnc.y, self.cnc.z)
            move_s_dz = self.cnc.dz

            self.cnc.motionEnd()
            move_f = (self.cnc.x, self.cnc.y, self.cnc.z)

            # at this point we have all the motion infos neede to generate
            # properly an event

            delta_z = move_f[2] - move_s[2]
            move_c = ((move_s[0], move_s[1], move_s[2]), delta_z,
                      (move_f[0], move_f[1], move_f[2]))

            OCV.min_z = min(OCV.min_z, move_f[2])
            OCV.max_z = max(OCV.max_z, move_f[2])

            # debug info useful only for development
            self.debug_info(line, move, move_s, move_f, delta_z)

            # analyze moves
            if move in ("G1", "G2", "G3"):
                # 'cut move' with feedrate
                if cmds[1][0] == "F":
                    if cmds[2][0] == "Z":
                        ev_label = "GMZ"
                    else:
                        ev_label = "GMXY"
                    OCV.blocks_ev.append(
                            (ev_label, l_idx, line, move_c, cmds))
                    OCV.blocks[-1].append(line)
                    continue
                else:
                    # 'cut move' with no feedrate, generally a plain move no
                    # event to process
                    OCV.blocks[-1].append(line)
            elif move == "G0":
                # original code using self.cnc.gcode == 0
                # will also detect come G0 move that don't contains Z value
                # leading to some 'false' positive
                if cmds[1][0] == "Z" and move_s_dz > 0.0:
                    # rapid Z move up detected
                    OCV.blocks_ev.append(("ZU", l_idx, line, move_c))
                    OCV.blocks[-1].append(line)
                    continue
                elif cmds[1][0] == "Z" and move_s_dz < 0:
                    # rapid Z move down detected
                    OCV.blocks_ev.append(("ZD", l_idx, line, move_c))
                    OCV.blocks[-1].append(line)
                elif cmds[1][0] == "Z" and move_s_dz == 0:
                    # Z neutral move this catch G0 Z(same level of prior move)
                    # that sometimes could appear in code
                    OCV.blocks_ev.append(("ZN", l_idx, line, move_c))
                    OCV.blocks[-1].append(line)
                else:
                    # a normal G0 move is detected
                    # this could catch "G0 Zxx" moves
                    OCV.blocks_ev.append(("G0", l_idx, line, move_c, cmds))
                    OCV.blocks[-1].append(line)
                    continue
            elif move in OCV.end_cmds:
                # catch the end commands
                OCV.blocks_ev.append((move, l_idx, line, move_c))
                OCV.blocks[-1].append(line)
            else:
                # other 'moves' T, M () not catched as end_cmds and S
                OCV.blocks[-1].append(line)

        # one line to pass the work to Heuristic module single that take care
        # of susbsequent work on parsing and block splitting
        Heuristic.process_blocks()

    def add_line(self, line):
        """plain addLine method from bCNC
        used by setLinesUndo method and if no postprocessor is detected in
        GCode file
        """
        if line.startswith("(-)"):
            return

        if line.startswith("(Block-name:"):
            self._blocksExist = True
            pat = OCV.RE_BLOCK.match(line)
            if pat:
                value = pat.group(2).strip()
                if not OCV.blocks or len(OCV.blocks[-1]):
                    OCV.blocks.append(Block(value))
                else:
                    OCV.blocks[-1].b_name = value
                return

        if not OCV.blocks:
            OCV.blocks.append(Block("Header"))

        cmds = Heuristic.parse_line(line)
        if cmds is None:
            OCV.blocks[-1].append(line)
            return

        self.cnc.motionStart(cmds)

        # rapid move up = end of block
        if self._blocksExist:
            OCV.blocks[-1].append(line)
        elif self.cnc.gcode == 0 and self.cnc.dz > 0.0:
            OCV.blocks[-1].append(line)
            OCV.blocks.append(Block())
        elif self.cnc.gcode == 0 and len(OCV.blocks) == 1:
            OCV.blocks.append(Block())
            OCV.blocks[-1].append(line)
        else:
            OCV.blocks[-1].append(line)

        self.cnc.motionEnd()

    def load(self, filename=None):
        """Load a file into editor"""
        if filename is None:
            filename = self.filename

        self.init()
        self.filename = filename

        try:
            f_handle = open(self.filename, "r")
        except Exception as e:
            return False

        self._lastModified = os.stat(self.filename).st_mtime

        self.cnc.initPath()
        self.cnc.resetAllMargins()
        self._blocksExist = False

        for line in f_handle:
            # Add line to the gcodelines used for display and heuristic
            OCV.gcodelines.append(line[:-1].replace("\x0d", ""))

        f_handle.close()

        self.parse_gcode(filename, False)

        return True

    def save(self, filename=None):
        """Save to a file"""
        if filename is not None:
            self.filename = filename

        try:
            f = open(self.filename, "w")
        except Exception:
            return False

        for block in OCV.blocks:
            block.write(f)
        f.close()
        self._lastModified = os.stat(self.filename).st_mtime
        self._modified = False
        return True

    def saveNGC(self, filename, comments=False):
        """Save in NGC format
        Cleaned from Block OKKCNC metadata with or without comments
        """
        f_handle = open(filename, 'w')
        for block in OCV.blocks:
            # print(block.enable)
            if block.enable:
                for line in block:
                    if comments is False:
                        cmds = Heuristic.parse_line(line)
                        # print(cmds)
                        if cmds is None:
                            continue

                    f_handle.write("{0}\n".format(line))

        f_handle.close()
        return True

    def saveOKK(self, filename):
        """Save in OKK format
        with OKKCNC metadata and comments
        """
        okkf = open(filename, 'w')
        for block in OCV.blocks:
            block.write(okkf)
        okkf.close()
        return True

    def addBlockFromString(self, name, text):

        if not text:
            return

        block = Block(name)
        block.extend(text.splitlines())
        OCV.blocks.append(block)

    def headerFooter(self):
        """Check if Block is empty:
             If empty insert a header and a footer
            """
        if not OCV.blocks:
            currDate = strftime("%Y-%m-%d - %H:%M:%S", localtime())
            curr_header = "(Created By {0} version {1}) \n".format(
                OCV.PRG_NAME, OCV.PRG_VER)
            curr_header += "(Date: {0})\n".format(currDate)
            curr_header += self.header

            self.addBlockFromString("Header", curr_header)
            self.addBlockFromString("Footer", self.footer)
            return True
        return False

    def toPath(self, bid):
        """convert a block to path"""
        block = OCV.blocks[bid]
        paths = []
        path = Path(block.name())
        self.initPath(bid)
        start = bmath.Vector(self.cnc.x, self.cnc.y)

        # get only first path that enters the surface
        # ignore the deeper ones
        passno = 0
        for line in block:
            # flatten helical paths
            line = re.sub(r"\s?z-?[0-9\.]+", "", line)

            # break after first depth pass
            if line == "( ---------- cut-here ---------- )":
                passno = 0
                if path:
                    paths.append(path)
                    path = Path(block.name())

            if line[:5] == "(pass":
                passno += 1

            if passno > 1:
                continue

            cmds = Heuristic.parse_line(line)

            if cmds is None:
                continue

            self.cnc.motionStart(cmds)
            end = bmath.Vector(self.cnc.xval, self.cnc.yval)
            if self.cnc.gcode == 0:  # rapid move (new block)
                if path:
                    paths.append(path)
                    path = Path(block.name())
            elif self.cnc.gcode == 1:  # line
                if self.cnc.dx != 0.0 or self.cnc.dy != 0.0:
                    path.append(Segment(1, start, end))
            elif self.cnc.gcode in (2, 3):  # arc
                xc, yc = self.cnc.motionCenter()
                center = bmath.Vector(xc, yc)
                path.append(Segment(self.cnc.gcode, start, end, center))
            self.cnc.motionEnd()
            start = end

        if path:
            paths.append(path)

        return paths

    def fromPath(self, path, block=None, z=None, retract=True, entry=False,
                 exit=True, zstart=None, ramp=None, comments=True,
                 exitpoint=None, truncate=None):
        """Create a block from Path
        @param z    I       ending depth
        @param zstart    I       starting depth
        """

        # Recursion for multiple paths
        if not isinstance(path, Path):
            block = Block("new")
            for p in path:
                block.extend(
                    self.fromPath(
                        p, None, z, retract, entry, exit,
                        zstart, ramp, comments, exitpoint, truncate))

                block.append("( ---------- cut-here ---------- )")
            del block[-1]  # remove trailing cut-here
            return block

        if z is None:
            z = self.cnc["surface"]

        if zstart is None:
            zstart = z

        # Calculate helix step
        zstep = abs(z-zstart)

        # Preprocess ramp
        if ramp is None:
            ramp = 0

        if ramp == 0:
            ramp = path.length()  # full helix (default)

        ramp = min(ramp, path.length())  # Never ramp longer than single pass!

        # Calculate helical feedrate
        helixfeed = self.cnc["cutfeed"]

        if zstep > 0:
            # Compensate helix feed
            # so we never plunge too fast on short/steep paths
            # FIXME: Add UI to disable this feature???
            # Not sure if that's needed.
            rampratio = zstep/min(path.length(), ramp)
            helixfeed2 = round(self.cnc["cutfeedz"] / rampratio)
            helixfeed = min(self.cnc["cutfeed"], helixfeed2)

        if block is None:
            if isinstance(path, Path):
                block = Block(path.name)
            else:
                block = Block(path[0].name)

    def syncFileTime(self):
        """sync file timestamp"""
        try:
            self._lastModified = os.stat(self.filename).st_mtime
        except Exception:
            return False

    def checkFile(self):
        """Check if a new version exists"""
        try:
            return os.stat(self.filename).st_mtime > self._lastModified
        except Exception:
            return False

    def undo(self):
        """Undo operation"""
        # print ">u>",self.undoredo.undoText()
        self.undoredo.undo()

    def redo(self):
        """Redo operation"""
        # print ">r>",self.undoredo.redoText()
        self.undoredo.redo()

    def addUndo(self, undoinfo, msg=None):

        if not undoinfo:
            return

        self.undoredo.add(undoinfo, msg)
        self._modified = True

    def canUndo(self):
        return self.undoredo.canUndo()

    def canRedo(self):
        return self.undoredo.canRedo()

    def setLinesUndo(self, lines):
        """Change all lines in editor"""
        undoinfo = (self.setLinesUndo, list(self.lines()))
        # Delete all blocks and create new ones
        del OCV.blocks[:]
        self.cnc.initPath()
        self._blocksExist = False

        for line in lines:
            self.add_line(line)

        Heuristic.trim_blocks()
        return undoinfo

    def setAllBlocksUndo(self, blocks=[]):
        undoinfo = [self.setAllBlocksUndo, OCV.blocks]
        OCV.blocks = blocks
        return undoinfo

    def setLineUndo(self, bid, lid, line):
        """Change a single line in a block"""
        undoinfo = (self.setLineUndo, bid, lid, OCV.blocks[bid][lid])
        OCV.blocks[bid][lid] = line
        return undoinfo

    def insLineUndo(self, bid, lid, line):
        """Insert a new line into block"""
        undoinfo = (self.delLineUndo, bid, lid)
        block = OCV.blocks[bid]

        if lid >= len(block):
            block.append(line)
        else:
            block.insert(lid, line)

        return undoinfo

    def cloneLineUndo(self, bid, lid):
        """Clone line inside a block"""
        return self.insLineUndo(bid, lid, OCV.blocks[bid][lid])

    def delLineUndo(self, bid, lid):
        """Delete line from block"""
        block = OCV.blocks[bid]
        undoinfo = (self.insLineUndo, bid, lid, block[lid])
        del block[lid]
        return undoinfo

    def addBlockUndo(self, bid, block):
        """Add a block"""

        if bid is None:
            bid = len(OCV.blocks)

        if bid >= len(OCV.blocks):
            undoinfo = (self.delBlockUndo, len(OCV.blocks))
            OCV.blocks.append(block)
        else:
            undoinfo = (self.delBlockUndo, bid)
            OCV.blocks.insert(bid, block)
        return undoinfo

    def cloneBlockUndo(self, bid, pos=None):
        """Clone a block"""
        if pos is None:
            pos = bid

        return self.addBlockUndo(pos, Block(OCV.blocks[bid]))

    def delBlockUndo(self, bid):
        """Delete a whole block"""
        block = OCV.blocks.pop(bid)
        undoinfo = (self.addBlockUndo, bid, block)
        return undoinfo

    def insBlocksUndo(self, bid, blocks):
        """Insert a list of other blocks from another gcode file probably"""
        if bid is None or bid >= len(OCV.blocks):
            bid = len(OCV.blocks)
        undoinfo = ("Insert blocks", self.delBlocksUndo, bid, bid+len(blocks))
        OCV.blocks[bid:bid] = blocks
        return undoinfo

    def delBlocksUndo(self, from_, to_):
        """Delete a range of blocks"""
        blocks = OCV.blocks[from_:to_]
        undoinfo = ("Delete blocks", self.insBlocksUndo, from_, blocks)
        del OCV.blocks[from_:to_]
        return undoinfo

    def insBlocks(self, bid, blocks, msg=""):
        """Insert blocks and push the undo info"""
        if self.headerFooter():    # just in case
            bid = 1
        self.addUndo(self.insBlocksUndo(bid, blocks), msg)

    def setBlockExpandUndo(self, bid, expand):
        """Set block expand"""
        undoinfo = (self.setBlockExpandUndo, bid, OCV.blocks[bid].expand)
        OCV.blocks[bid].expand = expand
        return undoinfo

    def setBlockEnableUndo(self, bid, enable):
        """Set block state"""
        undoinfo = (self.setBlockEnableUndo, bid, OCV.blocks[bid].enable)
        OCV.blocks[bid].enable = enable
        return undoinfo

    def setBlockColorUndo(self, bid, color):
        """Set block color"""
        undoinfo = (self.setBlockColorUndo, bid, OCV.blocks[bid].color)
        OCV.blocks[bid].color = color
        return undoinfo

    def swapBlockUndo(self, a, b):
        """Swap two blocks"""
        undoinfo = (self.swapBlockUndo, a, b)
        tmp = OCV.blocks[a]
        OCV.blocks[a] = OCV.blocks[b]
        OCV.blocks[b] = tmp
        return undoinfo

    def moveBlockUndo(self, src, dst):
        """Move block from location src to location dst"""
        if src == dst:
            return None

        undoinfo = (self.moveBlockUndo, dst, src)

        if dst > src:
            OCV.blocks.insert(dst-1, OCV.blocks.pop(src))
        else:
            OCV.blocks.insert(dst, OCV.blocks.pop(src))

        return undoinfo

    def invertBlocksUndo(self, blocks):
        """Invert selected blocks"""
        undoinfo = []
        first = 0
        last = len(blocks) - 1
        while first < last:
            undoinfo.append(self.swapBlockUndo(blocks[first], blocks[last]))
            first += 1
            last = 1
        return undoinfo

    def orderUpBlockUndo(self, bid):
        """Move block upwards"""
        if bid == 0:
            return None
        undoinfo = (self.orderDownBlockUndo, bid - 1)
        # swap with the block above
        before = OCV.blocks[bid-1]
        OCV.blocks[bid-1] = OCV.blocks[bid]
        OCV.blocks[bid] = before
        return undoinfo

    def orderDownBlockUndo(self, bid):
        """Move block downwards"""
        if bid >= len(OCV.blocks) - 1:
            return None
        undoinfo = (self.orderUpBlockUndo, bid+1)
        # swap with the block below
        after = self[bid+1]
        self[bid+1] = self[bid]
        self[bid] = after
        return undoinfo

    def insBlockLinesUndo(self, bid, lines):
        """Insert block lines"""
        undoinfo = (self.delBlockLinesUndo, bid)
        block = Block()
        for line in lines:
            block.append(line)
        OCV.blocks.insert(bid, block)
        return undoinfo

    def delBlockLinesUndo(self, bid):
        """Delete a whole block lines"""
        lines = [x for x in OCV.blocks[bid]]
        undoinfo = (self.insBlockLinesUndo, bid, lines)
        del OCV.blocks[bid]
        return undoinfo

    def setBlockNameUndo(self, bid, name):
        """Set Block name"""
        undoinfo = (self.setBlockNameUndo, bid, OCV.blocks[bid].b_name)
        OCV.blocks[bid].b_name = name
        return undoinfo

    def addBlockOperationUndo(self, bid, operation, remove=None):
        """Add an operation code in the name as [drill, cut, in/out...]"""
        undoinfo = (self.setBlockNameUndo, bid, OCV.blocks[bid].b_name)
        OCV.blocks[bid].addOperation(operation, remove)
        return undoinfo

    def setBlockLinesUndo(self, bid, lines):
        """Replace the lines of a block"""
        block = OCV.blocks[bid]
        undoinfo = (self.setBlockLinesUndo, bid, block[:])
        del block[:]
        block.extend(lines)
        return undoinfo

    def orderUpLineUndo(self, bid, lid):
        """Move line upwards"""
        if lid == 0:
            return None

        block = OCV.blocks[bid]
        undoinfo = (self.orderDownLineUndo, bid, lid-1)
        block.insert(lid-1, block.pop(lid))
        return undoinfo

    def orderDownLineUndo(self, bid, lid):
        """Move line downwards"""
        block = OCV.blocks[bid]

        if lid >= len(block) - 1:
            return None

        undoinfo = (self.orderUpLineUndo, bid, lid+1)
        block.insert(lid+1, block.pop(lid))
        return undoinfo

    def autolevelBlock(self, block):
        """Expand block with autolevel information"""
        new = []
        autolevel = not self.probe.isEmpty()
        for line in block:
            # newcmd = [] # seems to be not used
            cmds = CNC.compileLine(line)
            if cmds is None:
                new.append(line)
                continue
            elif isinstance(cmds, str):
                cmds = CNC.breakLine(cmds)
            else:
                new.append(line)
                continue

            self.cnc.motionStart(cmds)

            if autolevel and self.cnc.gcode in (0, 1, 2, 3) and\
                  self.cnc.mval == 0:

                xyz = self.cnc.motionPath()

                if not xyz:
                    # while auto-levelling, do not ignore non-movement
                    # commands, just append the line as-is
                    new.append(line)
                else:
                    extra = ""
                    for c in cmds:
                        if c[0].upper() not in (
                            'G', 'X', 'Y', 'Z',
                            'I', 'J', 'K', 'R'):

                            extra += c

                    x1, y1, z1 = xyz[0]

                    if self.cnc.gcode == 0:
                        g = 0
                    else:
                        g = 1

                    for x2, y2, z2 in xyz[1:]:
                        for x, y, z in self.probe.splitLine(
                                x1, y1, z1, x2, y2, z2):

                            new.append("G{0:d} {1} {2} {3} {4}".format(
                                g,
                                OCV.fmt('X', x/OCV.unit),
                                OCV.fmt('Y', y/OCV.unit),
                                OCV.fmt('Z', z/OCV.unit),
                                extra))

                            extra = ""
                        x1, y1, z1 = x2, y2, z2
                self.cnc.motionEnd()
            else:
                self.cnc.motionEnd()
                new.append(line)
        return new

    def autolevel(self, items):
        """Execute autolevel on selected blocks"""
        undoinfo = []
        operation = "autolevel"
        for bid in items:
            block = OCV.blocks[bid]

            if block.name() in ("Header", "Footer"):
                continue

            if not block.enable:
                continue

            lines = self.autolevelBlock(block)
            undoinfo.append(self.addBlockOperationUndo(bid, operation))
            undoinfo.append(self.setBlockLinesUndo(bid, lines))

        if undoinfo:
            self.addUndo(undoinfo)

    def __repr__(self):
        """Return string representation of whole file"""
        return "\n".join(list(self.lines()))

    def iterate(self, items):
        """Iterate over the items"""
        for bid, lid in items:
            if lid is None:
                block = OCV.blocks[bid]
                for i in range(len(block)):
                    yield bid, i
            else:
                yield bid, lid

    def lines(self):
        """Iterate over all lines"""
        for block in OCV.blocks:
            for line in block:
                yield line

    def initPath(self, bid=0):
        """initialize cnc path based on block bid"""
        if bid == 0:
            self.cnc.initPath()
        else:
            # Use the ending point of the previous block
            # since the starting (sxyz is after the rapid motion)
            block = OCV.blocks[bid-1]
            self.cnc.initPath(block.ex, block.ey, block.ez)

    def orderUp(self, items):
        """Move blocks/lines up"""
        sel = []  # new selection
        undoinfo = []
        for bid, lid in items:
            if isinstance(lid, int):
                undoinfo.append(self.orderUpLineUndo(bid, lid))
                sel.append((bid, lid - 1))
            elif lid is None:
                undoinfo.append(self.orderUpBlockUndo(bid))
                if bid == 0:
                    return items
                else:
                    sel.append((bid - 1, None))
        self.addUndo(undoinfo, "Move Up")
        return sel

    def orderDown(self, items):
        """Move blocks/lines down"""
        sel = []    # new selection
        undoinfo = []
        for bid, lid in reversed(items):
            if isinstance(lid, int):
                undoinfo.append(self.orderDownLineUndo(bid, lid))
                sel.append((bid, lid + 1))
            elif lid is None:
                undoinfo.append(self.orderDownBlockUndo(bid))
                if bid >= len(OCV.blocks) - 1:
                    return items
                else:
                    sel.append((bid + 1, None))
        self.addUndo(undoinfo, "Move Down")
        sel.reverse()
        return sel

    def close(self, items):
        """Close paths by joining end with start with a line segment"""
        undoinfo = []
        for bid in items:
            block = OCV.blocks[bid]

            if block.name() in ("Header", "Footer"):
                continue

            undoinfo.append(self.insLineUndo(
                bid, OCV.MAXINT,
                self.cnc.gline(block.sx, block.sy)))
        self.addUndo(undoinfo)

    def info(self, bid):
        """Return information for a block
           return XXX
        """
        # block = OCV.blocks[bid] # seems to be unused
        paths = self.toPath(bid)

        if not paths:
            return None, 1

        if len(paths) > 1:
            closed = paths[0].isClosed()
            return int(closed), paths[0]._direction(closed)
            # No treatment for closed not 0 or 1 or None
            # len(paths) could return 2 or plus
            # return len(paths), paths[0]._direction(closed)
        else:
            closed = paths[0].isClosed()
            return int(closed), paths[0]._direction(closed)

    def modify(self, items, func, tabFunc, *args):
        """Modify the lines according to the supplied function and arguments"""
        undoinfo = []
        old = {}  # Motion commands: Last value
        new = {}  # Motion commands: New value
        relative = False

        for bid, lid in self.iterate(items):
            block = OCV.blocks[bid]

            if isinstance(lid, int):
                cmds = Heuristic.parse_line(block[lid])

                if cmds is None:
                    continue

                self.cnc.motionStart(cmds)

                # Collect all values
                new.clear()
                for cmd in cmds:

                    if cmd.upper() == 'G91':
                        relative = True
                    if cmd.upper() == 'G90':
                        relative = False

                    c = cmd[0].upper()
                    # record only coordinates commands
                    if c not in "XYZIJKR":
                        continue

                    try:
                        new[c] = old[c] = float(cmd[1:])*OCV.unit
                    except Exception:
                        new[c] = old[c] = 0.0

                # Modify values with func
                if func(new, old, relative, *args):
                    # Reconstruct new line
                    newcmd = []
                    present = ""
                    for cmd in cmds:
                        c = cmd[0].upper()
                        if c in "XYZIJKR":
                            # Coordinates
                            newcmd.append(OCV.fmt(c, new[c]/OCV.unit))
                        elif c == "G" and int(cmd[1:]) in (0, 1, 2, 3):
                            # Motion
                            newcmd.append("G{0}".format(self.cnc.gcode))
                        else:
                            # the rest leave unchanged
                            newcmd.append(cmd)
                        present += c
                    # Append motion commands if not exist and changed
                    check = "XYZ"

                    if 'I' in new or 'J' in new or 'K' in new:
                        check += "IJK"

                    for c in check:
                        try:
                            if c not in present and new.get(c) != old.get(c):
                                newcmd.append(
                                    OCV.fmt(c, new[c]/OCV.unit))
                        except Exception:
                            pass

                    undoinfo.append(
                        self.setLineUndo(bid, lid, " ".join(newcmd)))

                self.cnc.motionEnd()
                # reset arc offsets

                for i in "IJK":
                    if i in old:
                        old[i] = 0.0

        # FIXME I should add it later, check all functions using it
        self.addUndo(undoinfo)

    def moveFunc(self, new, old, relative, dx, dy, dz):
        """Move position by dx,dy,dz"""
        if relative:
            return False

        changed = False

        if 'X' in new:
            changed = True
            new['X'] += dx

        if 'Y' in new:
            changed = True
            new['Y'] += dy

        if 'Z' in new:
            changed = True
            new['Z'] += dz

        return changed

    def orderLines(self, items, direction):
        """Order Lines"""
        if direction == "UP":
            self.orderUp(items)
        elif direction == "DOWN":
            self.orderDown(items)
        else:
            pass

    def moveLines(self, items, dx, dy, dz=0.0):
        """Move position by dx,dy,dz"""
        return self.modify(items, self.moveFunc, None, dx, dy, dz)

    def rotateFunc(self, new, old, relative, c, s, x0, y0):
        """Rotate position by
           c(osine), s(ine) of an angle around center (x0,y0)
        """

        if 'X' not in new and 'Y' not in new:
            return False

        x = get_dict_value('X', new, old)

        y = get_dict_value('Y', new, old)

        new['X'] = c*(x-x0) - s*(y-y0) + x0

        new['Y'] = s*(x-x0) + c*(y-y0) + y0

        if 'I' in new or 'J' in new:
            i = get_dict_value('I', new, old)
            j = get_dict_value('J', new, old)

            if self.cnc.plane in (OCV.CNC_XY, OCV.CNC_XZ):
                new['I'] = c*i - s*j

            if self.cnc.plane in (OCV.CNC_XY, OCV.CNC_YZ):
                new['J'] = s*i + c*j

        return True

    def transformFunc(self, new, old, relative, c, s, xo, yo):
        """Transform (rototranslate) position with the following function:
           xn = c*x - s*y + xo
           yn = s*x + c*y + yo
           it is like the rotate but the rotation center is not defined
           """

        if 'X' not in new and 'Y' not in new:
            return False

        x = get_dict_value('X', new, old)
        y = get_dict_value('Y', new, old)
        new['X'] = c*x - s*y + xo
        new['Y'] = s*x + c*y + yo

        if 'I' in new or 'J' in new:
            i = get_dict_value('I', new, old)
            j = get_dict_value('J', new, old)
            new['I'] = c*i - s*j
            new['J'] = s*i + c*j
        return True

    def rotateLines(self, items, ang, x0=0.0, y0=0.0):
        """Rotate items around optional center (on XY plane)
           ang in degrees (counter-clockwise)
           """

        a = math.radians(ang)
        c = math.cos(a)
        s = math.sin(a)

        if ang in (0.0, 90.0, 180.0, 270.0, -90.0, -180.0, -270.0):
            # round numbers to avoid nasty extra digits
            c = round(c)
            s = round(s)
        return self.modify(items, self.rotateFunc, None, c, s, x0, y0)

    def orientLines(self, items):
        """Use the orientation information to orient selected code"""

        if not self.orient.valid:
            return "ERROR: Orientation information is not valid"

        c = math.cos(self.orient.phi)
        s = math.sin(self.orient.phi)

        return self.modify(
            items,
            self.transformFunc,
            None,
            c, s,
            self.orient.xo, self.orient.yo)

    def mirrorHFunc(self, new, old, relative, *kw):
        """Mirror Horizontal"""
        changed = False
        for axis in 'XI':
            if axis in new:
                new[axis] = -new[axis]
                changed = True
        if self.cnc.gcode in (2, 3):    # Change  2<->3
            self.cnc.gcode = 5 - self.cnc.gcode
            changed = True
        return changed

    def mirrorVFunc(self, new, old, relative, *kw):
        """Mirror Vertical"""
        changed = False
        for axis in 'YJ':
            if axis in new:
                new[axis] = -new[axis]
                changed = True
        if self.cnc.gcode in (2, 3):    # Change  2<->3
            self.cnc.gcode = 5 - self.cnc.gcode
            changed = True
        return changed

    def mirrorHLines(self, items):
        """Mirror horizontally"""
        return self.modify(items, self.mirrorHFunc, None)

    def mirrorVLines(self, items):
        """"Mirror vertically"""
        return self.modify(items, self.mirrorVFunc, None)

    def roundFunc(self, new, old, relative):
        """Round all digits with accuracy"""
        for name, value in new.items():
            new[name] = round(value, OCV.digits)
        return bool(new)

    def roundLines(self, items, acc=None):
        """Round line by the amount of digits"""
        if acc is not None:
            OCV.digits = acc

        return self.modify(items, self.roundFunc, None)

    def removeNlines(self, items):
        """Remove the line number for lines"""
        pass

    def optimize(self, items):
        """Re-arrange using genetic algorithms a set of blocks to minimize
           rapid movements.
        """
        n = len(items)

        matrix = []
        for i in range(n):
            matrix.append([0.0] * n)

        # Find distances between blocks (end to start)
        for i in range(n):
            block = OCV.blocks[items[i]]
            x1 = block.ex
            y1 = block.ey
            for j in range(n):
                if i == j:
                    continue
                block = OCV.blocks[items[j]]
                x2 = block.sx
                y2 = block.sy
                dx = x1-x2
                dy = y1-y2
                # Compensate for machines,
                # which have different speed of X and Y:
                dx /= OCV.feedmax_x
                dy /= OCV.feedmax_y
                matrix[i][j] = math.sqrt(dx*dx + dy*dy)
#         from pprint import pprint
#         pprint(matrix)

        best = [0]
        unvisited = range(1, n)
        while unvisited:
            last = best[-1]
            row = matrix[last]
            # from all the unvisited places search the closest one
            mindist = 1e30

            for i, u in enumerate(unvisited):
                d = row[u]

                if d < mindist:
                    mindist = d
                    si = i

            best.append(unvisited.pop(si))
        # print "best=",best

        undoinfo = []
        for i in range(len(best)):
            b = best[i]

            if i == b:
                continue

            ptr = best.index(i)
            # swap i,b in items
            undoinfo.append(self.swapBlockUndo(items[i], items[b]))
            # swap i,ptr in best
            best[i], best[ptr] = best[ptr], best[i]
        self.addUndo(undoinfo, "Optimize")

    def comp_level(self, queue, stopFunc=None):
        """Use probe information (if exist) to modify the g-code to autolevel"""
      
        paths = []
        # empty the gctos value
        OCV.gctos = []

        def add(line, path):
            if line is not None:
                if isinstance(line, str):
                    queue.put(line + "\n")
                    OCV.gctos.append(line)
                else:
                    queue.put(line)
                    OCV.gctos.append(line)

            paths.append(path)
        
        # check the existence of an autolevel file        
        autolevel = not self.probe.isEmpty()

        self.initPath()

        for line in CNC.compile_pgm(OCV.startup.splitlines()):
            add(line, None)

        every = 1
        for i, block in enumerate(OCV.blocks):

            if not block.enable:
                continue

            for j, line in enumerate(block):
                every -= 1
                if every <= 0:
                    if stopFunc is not None and stopFunc():
                        return None
                    every = 50

                newcmd = []
                cmds = CNC.compileLine(line)
                if cmds is None:
                    continue
                elif isinstance(cmds, str):
                    cmds = CNC.breakLine(cmds)
                else:
                    # either CodeType or tuple, list[] append at it as is
                    if isinstance(cmds, types.CodeType) or\
                          isinstance(cmds, int):
                        add(cmds, None)
                    else:
                        add(cmds, (i, j))
                    continue

                skip = False
                expand = None
                self.cnc.motionStart(cmds)

                # FIXME append feed on cut commands.
                # It will be obsolete in grbl v1.0
                if OCV.appendFeed and self.cnc.gcode in (1, 2, 3):
                    # Check is not existing in cmds
                    for c in cmds:
                        if c[0] in ('f', 'F'):
                            break
                    else:
                        cmds.append(
                            OCV.fmt(
                                'F',
                                self.cnc.feed / OCV.unit))

                if autolevel and self.cnc.gcode in (0, 1, 2, 3) and \
                      self.cnc.mval == 0:
                    xyz = self.cnc.motionPath()

                    if not xyz:
                        # while auto-levelling, do not ignore non-movement
                        # commands, just append the line as-is
                        add(line, None)
                    else:
                        extra = ""
                        for c in cmds:
                            if c[0].upper() not in (
                                    'G', 'X', 'Y', 'Z', 'I', 'J', 'K', 'R'):
                                extra += c
                        x1, y1, z1 = xyz[0]
                        if self.cnc.gcode == 0:
                            g = 0
                        else:
                            g = 1
                        for x2, y2, z2 in xyz[1:]:
                            for x, y, z in self.probe.splitLine(
                                    x1, y1, z1, x2, y2, z2):
                                add("G{0:d} {1} {2} {3} {4}".format(
                                    g,
                                    OCV.fmt('X', x/OCV.unit),
                                    OCV.fmt('Y', y/OCV.unit),
                                    OCV.fmt('Z', z/OCV.unit),
                                    extra),
                                    (i, j))

                                extra = ""

                            x1, y1, z1 = x2, y2, z2
                    self.cnc.motionEnd()
                    continue
                else:
                    # FIXME expansion policy here variable needed
                    # Canned cycles
                    if OCV.drillPolicy == 1 and \
                       self.cnc.gcode in (81, 82, 83, 85, 86, 89):
                        expand = self.cnc.macroGroupG8X()
                    # Tool change
                    elif self.cnc.mval == 6:
                        if OCV.toolPolicy == 0:
                            # send to grbl
                            pass
                        elif OCV.toolPolicy == 1:
                            # skip whole line
                            skip = True
                        elif OCV.toolPolicy >= 2:
                            expand = CNC.compile_pgm(self.cnc.toolChange())
                    self.cnc.motionEnd()

                if expand is not None:
                    for line in expand:
                        add(line, None)
                    expand = None
                    continue
                elif skip:
                    skip = False
                    continue

                for cmd in cmds:
                    c = cmd[0]
                    try:
                        value = float(cmd[1:])
                    except Exception:
                        value = 0.0

                    if c.upper() in (
                            "F", "X", "Y", "Z",
                            "I", "J", "K", "R", "P"):

                        cmd = OCV.fmt(c, value)
                    else:
                        opt = OCV.ERROR_HANDLING.get(cmd.upper(), 0)

                        if opt == OCV.GSTATE_SKIP:
                            cmd = None

                    if cmd is not None:
                        newcmd.append(cmd)

                add("".join(newcmd), (i, j))

        return paths
Esempio n. 25
0
    def calc(self, N, phi, Pc):
        N = abs(N)
        # Pitch Circle
        D = N * Pc / math.pi
        R = D / 2.0

        # Diametrical pitch
        Pd = N / D

        # Base Circle
        Db = D * math.cos(phi)
        Rb = Db / 2.0

        # Addendum
        a = 1.0 / Pd

        # Outside Circle
        Ro = R + a
        Do = 2.0 * Ro

        # Tooth thickness
        T = math.pi * D / (2 * N)

        # undercut?
        U = 2.0 / (math.sin(phi) * (math.sin(phi)))
        needs_undercut = N < U
        # sys.stderr.write("N:%s R:%s Rb:%s\n" % (N,R,Rb))

        # Clearance
        c = 0.0
        # Dedendum
        b = a + c

        # Root Circle
        Rr = R - b
        Dr = 2.0 * Rr

        two_pi = 2.0 * math.pi
        half_thick_angle = two_pi / (4.0 * N)
        pitch_to_base_angle = self.involute_intersect_angle(Rb, R)
        pitch_to_outer_angle = self.involute_intersect_angle(
            Rb, Ro)  # pitch_to_base_angle

        points = []
        for x in range(1, N + 1):
            c = x * two_pi / N

            # angles
            pitch1 = c - half_thick_angle
            base1 = pitch1 - pitch_to_base_angle
            outer1 = pitch1 + pitch_to_outer_angle

            pitch2 = c + half_thick_angle
            base2 = pitch2 + pitch_to_base_angle
            outer2 = pitch2 - pitch_to_outer_angle

            # points
            b1 = self.point_on_circle(Rb, base1)
            p1 = self.point_on_circle(R, pitch1)
            o1 = self.point_on_circle(Ro, outer1)
            o2 = self.point_on_circle(Ro, outer2)
            p2 = self.point_on_circle(R, pitch2)
            b2 = self.point_on_circle(Rb, base2)

            if Rr >= Rb:
                pitch_to_root_angle = pitch_to_base_angle - self.involute_intersect_angle(
                    Rb, Rr)
                root1 = pitch1 - pitch_to_root_angle
                root2 = pitch2 + pitch_to_root_angle
                r1 = self.point_on_circle(Rr, root1)
                r2 = self.point_on_circle(Rr, root2)

                points.append(r1)
                points.append(p1)
                points.append(o1)
                points.append(o2)
                points.append(p2)
                points.append(r2)
            else:
                r1 = self.point_on_circle(Rr, base1)
                r2 = self.point_on_circle(Rr, base2)
                points.append(r1)
                points.append(b1)
                points.append(p1)
                points.append(o1)
                points.append(o2)
                points.append(p2)
                points.append(b2)
                points.append(r2)

        first = points[0]
        del points[0]

        blocks = []
        block = Block(self.name)
        blocks.append(block)

        block.append(CNC.grapid(first.x(), first.y()))
        block.append(CNC.zenter(0.0))
        #print first.x(), first.y()
        for v in points:
            block.append(CNC.gline(v.x(), v.y()))
            #print v.x(), v.y()
        #print first.x(), first.y()
        block.append(CNC.gline(first.x(), first.y()))
        block.append(CNC.zsafe())

        #block = Block("%s-center"%(self.name))
        block = Block("%s-basecircle" % (self.name))
        block.enable = False
        block.append(CNC.grapid(Db / 2, 0.))
        block.append(CNC.zenter(0.0))
        block.append(CNC.garc(CW, Db / 2, 0., i=-Db / 2))
        block.append(CNC.zsafe())
        blocks.append(block)
        return blocks
Esempio n. 26
0
def mop(self, app, mem_0, mem_1, mop_type):
    """create GCode for a pocket
    Values are stored in OCV.mop_vars as a dictionary"""

    end_depth = OCV.mop_vars["tdp"]
    x_start = min(OCV.WK_mems[mem_0][0], OCV.WK_mems[mem_1][0])
    y_start = min(OCV.WK_mems[mem_0][1], OCV.WK_mems[mem_1][1])

    x_end = max(OCV.WK_mems[mem_0][0], OCV.WK_mems[mem_1][0])
    y_end = max(OCV.WK_mems[mem_0][1], OCV.WK_mems[mem_1][1])

    z_start = OCV.WK_mems[mem_1][2]

    tool_dia = OCV.mop_vars["tdia"]
    tool_rad = tool_dia / 2.

    xy_stepover = OCV.mop_vars["mso"]

    z_stepover = OCV.mop_vars["msd"]

    # avoid infinite while loop
    if z_stepover == 0:
        z_stepover = 0.001

    if mop_type == "PK":
        # Pocketing
        isSpiral = OCV.mop_vars["pks"]

        isInt = OCV.mop_vars["sin"]

        if isSpiral is True:
            op_name = "Spiral Pocket"
        else:
            op_name = "Rectangular Pocket"

    elif mop_type == "LN":
        op_name = "Line"


    """
    cut_dir passed to the calculation method depends on starting point,
    If we cut from internal we minimize "full stock" cut
    in which the endmill is 'surrounded' by the material.
    For calculation these assumptions are done, maybe is wrong

    Conventionl cut is when piece is cut on left side of the cutter

    Climb cut is when piece is cut on right side
    """

    if mop_type == "PK":
        # Pocketing
        if isInt is True:
            cut_dir = 1
            reverse = True
        else:
            cut_dir = 0
            reverse = False

    msg = (
        "{} Operation: \n\n".format(op_name),
        "Start: \n\n{0}\n\n".format(OCV.showC(x_start, y_start, z_start)),
        "End: \n\n{0}\n\n".format(OCV.showC(x_end, y_end, end_depth)),
        "Tool diameter: {0:.{1}f} \n\n".format(tool_dia, OCV.digits),
        "StepDown: {0:.{1}f} \n\n".format(z_stepover, OCV.digits),
        "StepOver: {0:.{1}f} \n\n".format(xy_stepover, OCV.digits))

    retval = tkMessageBox.askokcancel(
        "MOP {} Cut".format(op_name), "".join(msg))

    if retval is False:
        return

    # Start Calculations

    start = (x_start, y_start)
    end = (x_end, y_end)

    if mop_type == "PK":
            # Pocketing
        # Assign points here
        if isSpiral is True:
            msg,x_p,y_p = spiral_pocket(start, end, tool_rad, xy_stepover, cut_dir)
        else:
            msg,x_p,y_p = spiral_pocket(start, end, tool_rad, xy_stepover, cut_dir)

        if msg != "OK":
            retval = tkMessageBox.askokcancel(op_name, msg)
            return

        if reverse is True:
            x_p.reverse()
            y_p.reverse()

    # Reset the editor and write the Gcode generated Here
    OCV.TK_MAIN.clear_gcode()
    OCV.TK_MAIN.clear_editor()
    OCV.TK_MAIN.reset_canvas()
    blocks = []
    block = Block.Block("Init")
    # Get the current WCS as the mem are related to it
    block.append(OCV.CD['WCS'])
    blocks.append(block)

    block = Block.Block(op_name)
    block.append("({})".format(op_name))
    block.append("(Tool diameter = {0:.{1}f})".format(tool_dia, OCV.digits))
    block.append("(Start: {0})".format(OCV.gcodeCC(x_start, y_start, z_start)))
    block.append("(End: {0})".format(OCV.gcodeCC(x_end, y_end, end_depth)))
    block.append("(StepDown: {0:.{1}f} )".format(z_stepover, OCV.digits))
    block.append("(StepOver: {0:.{1}f} )".format(xy_stepover, OCV.digits))

    if mop_type == "PK":
            # Pocketing
            # Move safe to first point
        block.append(CNC.zsafe())
        block.append(CNC.grapid(x_p[0], y_p[0]))
    elif mop_type == "LN":
        # Move safe to first point
        block.append(CNC.zsafe())
        block.append(CNC.grapid(x_start, y_start))
    else:
        return

    # the check is done at the final depth
    curr_depth = z_start

    print("curr_depth, z_start", curr_depth, z_start)
    # Create GCode from points
    while True:
        curr_depth -= z_stepover

        if curr_depth < end_depth:
            curr_depth = end_depth

        block.append(CNC.zenter(curr_depth))
        block.append(CNC.gcode_string(1, [("F", OCV.CD["cutfeed"])]))

        if mop_type == "PK":
            # Pocketing
            for x_l, y_l in zip(x_p, y_p):
                block.append(CNC.gline(x_l, y_l))

            # Move to the begin in a safe way
            block.append(CNC.zsafe())
            block.append(CNC.grapid(x_p[0], y_p[0]))

        elif mop_type == "LN":
            block.append(CNC.gline(x_end, y_end))
            # Move to the begin in a safe way
            block.append(CNC.zsafe())
            block.append(CNC.grapid(x_start, y_start))

        # Verify exit condition
        if curr_depth <= end_depth:
            break

    # end of the loop
    # return to z_safe
    block.append(CNC.zsafe())
    blocks.append(block)

    if blocks is not None:
        active = OCV.TK_MAIN.activeBlock()

        if active == 0:
            active = 1

        OCV.TK_MAIN.gcode.insBlocks(active, blocks, op_name)
        OCV.TK_MAIN.refresh()
        OCV.TK_MAIN.setStatus(_("{}: GCode Generated".format(op_name)))
Esempio n. 27
0
	def make(self,app, XStart=0.0, YStart=0.0, FlatWidth=10., FlatHeight=10., \
			FlatDepth=0, BorderPass=False, CutDirection="Climb", PocketType="Raster"):

		#GCode Blocks
		blocks = []

		#Check parameters
		if CutDirection is "":
			app.setStatus(_("Flatten abort: Cut Direction is undefined"))
			return

		if PocketType is "":
			app.setStatus(_("Flatten abort: Pocket Type is undefined"))
			return

		if FlatWidth <= 0 or FlatHeight <= 0 :
			app.setStatus(_("Flatten abort: Flatten Area dimensions must be > 0"))
			return

		if FlatDepth > 0 :
			app.setStatus(_("Flatten abort: Hey this is only for subtractive machine! Check depth!"))
			return

		#Add Region disabled to show worked area
		block = Block(self.name + " Outline")
		block.enable = False
		block.append(CNC.zsafe())
		xR,yR = self.RectPath(XStart,YStart,FlatWidth,FlatHeight)
		for x,y in zip(xR,yR):
			block.append(CNC.gline(x,y))
		blocks.append(block)

		# Load tool and material settings
		toolDiam = CNC.vars['diameter']
		toolRadius = toolDiam / 2.

		#Calc tool diameter with Maximum Step Over allowed
		StepOverInUnitMax = toolDiam * CNC.vars['stepover'] / 100.0

		#Offset for Border Cut
		BorderXStart = XStart + toolRadius
		BorderYStart = YStart + toolRadius
		BorderWidth = FlatWidth - toolDiam
		BorderHeight = FlatHeight - toolDiam
		BorderXEnd = XStart + FlatWidth - toolRadius
		BorderYEnd = YStart + FlatHeight - toolRadius

		PocketXStart = BorderXStart
		PocketYStart = BorderYStart
		PocketXEnd = BorderXEnd
		PocketYEnd = BorderYEnd

		#Calc space to work with/without border cut
		WToWork = FlatWidth - toolDiam
		HToWork = FlatHeight - toolDiam

		if(WToWork < toolRadius or HToWork < toolRadius):
			app.setStatus(_("Flatten abort: Flatten area is too small for this End Mill."))
			return

		#Prepare points for pocketing
		xP=[]
		yP=[]
        #and border
		xB=[]
		yB=[]

        #---------------------------------------------------------------------
        #Raster approach
		if PocketType == "Raster":
			#Correct sizes if border is used
			if(BorderPass):
				PocketXStart += StepOverInUnitMax
				PocketYStart += StepOverInUnitMax
				PocketXEnd -= StepOverInUnitMax
				PocketYEnd -= StepOverInUnitMax
				WToWork -= (StepOverInUnitMax)
				HToWork -= (StepOverInUnitMax)

			#Calc number of pass
			VerticalCount = (int)(HToWork / StepOverInUnitMax)
			#Calc step minor of Max step
			StepOverInUnit = HToWork / (VerticalCount +1)
			flip = False
			ActualY = PocketYStart
			#Zig zag
			if StepOverInUnit==0 : StepOverInUnit=0.001  #avoid infinite while loop
			while (True):
				#Zig
				xP.append(self.ZigZag(flip,PocketXStart,PocketXEnd))
				yP.append(ActualY)
				flip = not flip
				#Zag
				xP.append(self.ZigZag(flip,PocketXStart,PocketXEnd))
				yP.append(ActualY)
				if(ActualY >= PocketYEnd - StepOverInUnitMax + StepOverInUnit):
					break
				#Up
				ActualY += StepOverInUnit
				xP.append(self.ZigZag(flip,PocketXStart,PocketXEnd))
				yP.append(ActualY)

			#Points for border cut depends on Zig/Zag end
			if(BorderPass):
				if flip:
					xB,yB = self.RectPath(BorderXStart,BorderYEnd,BorderWidth,-BorderHeight)
				else:
					xB,yB = self.RectPath(BorderXEnd,BorderYEnd,-BorderWidth,-BorderHeight)

				#Reverse in case of Climb
				if CutDirection == "Climb":
					xB = xB[::-1]
					yB = yB[::-1]

		#---------------------------------------------------------------------
        #Offset approach
		if PocketType == "Offset":
			#Calc number of pass
			VerticalCount = (int)(HToWork / StepOverInUnitMax)
			HorrizontalCount = (int)(WToWork / StepOverInUnitMax)
			#Make them odd
			if VerticalCount%2 == 0 : VerticalCount += 1
			if HorrizontalCount%2 == 0 : HorrizontalCount += 1
			#Calc step minor of Max step
			StepOverInUnitH = HToWork / (VerticalCount)
			StepOverInUnitW = WToWork / (HorrizontalCount)

			#Start from border to center
			xS = PocketXStart
			yS = PocketYStart
			wS = WToWork
			hS = HToWork
			xC = 0
			yC = 0
			while (xC<=HorrizontalCount/2 and yC<=VerticalCount/2):
				#Pocket offset points
				xO,yO = self.RectPath(xS, yS, wS, hS)
				if CutDirection == "Conventional":
					xO = xO[::-1]
					yO = yO[::-1]

				xP = xP + xO
				yP = yP + yO
				xS+=StepOverInUnitH
				yS+=StepOverInUnitW
				hS-=2.0*StepOverInUnitH
				wS-=2.0*StepOverInUnitW
				xC += 1
				yC += 1

			#Reverse point to start from inside (less stres on the tool)
			xP = xP[::-1]
			yP = yP[::-1]

		#Blocks for pocketing
		block = Block(self.name)
		block.append("(Flatten from X=%g Y=%g)"%(XStart,YStart))
		block.append("(W=%g x H=%g x D=%g)"%(FlatWidth,FlatHeight,FlatDepth))
		block.append("(Approach: %s %s)" % (PocketType,CutDirection))
		if BorderPass : block.append("(with border)")

		#Move safe to first point
		block.append(CNC.zsafe())
		block.append(CNC.grapid(xP[0],yP[0]))
		#Init Depth
		currDepth = 0.
		stepz = CNC.vars['stepz']
		if stepz==0 : stepz=0.001  #avoid infinite while loop

		#Create GCode from points
		while True:
			currDepth -= stepz
			if currDepth < FlatDepth : currDepth = FlatDepth
			block.append(CNC.zenter(currDepth))
			block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])]))

			#Pocketing
			for x,y in zip(xP,yP):
				block.append(CNC.gline(x,y))

			#Border cut if request
			for x,y in zip(xB,yB):
				block.append(CNC.gline(x,y))

			#Verify exit condition
			if currDepth <= FlatDepth : break

			#Move to the begin in a safe way
			block.append(CNC.zsafe())
			block.append(CNC.grapid(xP[0],yP[0]))

		#Zsafe
		block.append(CNC.zsafe())
		blocks.append(block)
		return blocks
Esempio n. 28
0
	def execute(self, app):
		name = self["name"]
		if not name or name=="default": name="Default Name"
		sel_Blocks = self["Sel_Blocks"]
		#Get inputs
		x = self["X"]
		y = self["Y"]
		z = self["Z"]
		if z == "":
			z=CNC.vars["surface"]

		cutDiam = self["CutDiam"]
		cutRadius = cutDiam/2.0
		if self["endmill"]:
			self.master["endmill"].makeCurrent(self["endmill"])
		toolDiam = CNC.vars["diameter"]
		#Radio = self["RadioHelix"]
		pitch = self["Pitch"]
		Depth = self["Depth"]
		Mult_F_Z = self["Mult_Feed_Z"]
		helicalCut = self["HelicalCut"]
		clearanceEntry = self["ClearanceEntry"]
		clearanceExit = self["ClearanceExit"]
		clearance = clearanceEntry
		entry = self["Entry"]
		returnToSafeZ = self["ReturnToSafeZ"]

		toolDiam = CNC.vars['diameter']
		toolRadius = toolDiam/2.0
		Radio = cutRadius - toolRadius
		if(Radio < 0): Radio = 0

		toolDiam = CNC.vars['diameter']
		toolRadius = toolDiam/2.0
		Radio = cutRadius - toolRadius

		if clearanceEntry =="":
			clearanceEntry =0 
		if clearanceExit =="":
			clearanceExit =0 

		if helicalCut == "Helical Cut":
			turn = 2
			p="HelicalCut "
		elif helicalCut == "Internal Right Thread":
			turn = 2
			p= "IntRightThread "
		elif helicalCut == "Internal Left Thread":
			turn = 3
			p= "IntLeftThread "
		elif helicalCut == "External Right Thread":
			Radio = cutRadius + toolRadius
			turn = 2
			p= "ExtRightThread "
		elif helicalCut == "External Left Thread":
			Radio = cutRadius + toolRadius
			turn = 3
			p= "ExtLeftThread "

# 		------------------------------------------------------------------------------------------------------------------		
		#Check inputs
		if sel_Blocks == 0:
			if x == "" or y == "" :
				app.setStatus(_("If block selected false, please make a value of x"))
				return

		elif helicalCut == "":
			app.setStatus(_("Helical Abort: Please select helical type"))
			return

		elif cutDiam < toolDiam or cutDiam == "":
			app.setStatus(_("Helical Abort: Helix diameter must be greater than the end mill"))
			return

		elif cutDiam <= 0:
			app.setStatus(_("Helical Abort: Helix diameter must be positive"))
			return

		elif pitch <= 0 or pitch =="":
			app.setStatus(_("Helical Abort: Drop must be greater than 0"))
			return

		elif Mult_F_Z <= 0 or Mult_F_Z == "":
			app.setStatus(_("Helical Abort: Z Feed Multiplier must be greater than 0"))
			return

		elif entry == "":
			app.setStatus(_("Helical Abort: Please selecte Entry and Exit type"))
			return

		elif clearanceEntry < 0 or clearanceEntry == "":
			app.setStatus(_("Helical Abort: Entry Edge Clearence may be positive"))
			return

		elif clearanceExit < 0 or clearanceExit == "":
			app.setStatus(_("Helical Abort: Exit Edge Clearence may be positive"))
			return
# 		------------------------------------------------------------------------------------------------------------------		
		#Initialize blocks that will contain our gCode
		blocks = []
		#block = Block(name)
		block = Block( p + str(cutDiam) + " Pitch " + str(pitch) + " Bit " + str(toolDiam) + " depth " + str(Depth))
		
		cutFeed = CNC.vars["cutfeedz"]	#<<< Get cut feed Z for the current material
		cutFeedMax = CNC.vars["cutfeed"] #<<< Get cut feed XY for the current material
# 		------------------------------------------------------------------------------------------------------------------
		# Get selected blocks from editor
		selBlocks = app.editor.getSelectedBlocks()
		if not selBlocks:
			app.editor.selectAll()
			selBlocks = app.editor.getSelectedBlocks()

		if not selBlocks:
			if sel_Blocks == 1:
				app.setStatus(_("Helical abort: Please select some path"))
				return
# 		------------------------------------------------------------------------------------------------------------------
		# Get selected blocks from editor
		if sel_Blocks == 1:
			selBlocks = app.editor.getSelectedBlocks()
			if not selBlocks:
				app.editor.selectAll()
				selBlocks = app.editor.getSelectedBlocks()

			#Get all segments from gcode
			allSegments = self.extractAllSegments(app,selBlocks)

			#Create holes locations
			allHoles=[]
			for bidSegment in allSegments:
				if len(bidSegment)==0:
					continue

				bidHoles = []
				for idx, anchor in enumerate(bidSegment):
					if idx ==2:
						newHolePoint = (anchor[0][0],anchor[0][1],anchor[0][2])
						bidHoles.append(newHolePoint)


				#Add bidHoles to allHoles
				allHoles.append(bidHoles)

# 		------------------------------------------------------------------------------------------------------------------
			holesCount = 0
			for bid in allHoles:
				for xH,yH,zH in bid:
					x = xH
					y = yH

# 		------------------------------------------------------------------------------------------------------------------
#		 Init: Adjust feed and rapid move to Z safe 
		
		if Mult_F_Z is"":
			Mult_F_Z = 1

		if Mult_F_Z == 0:
			Mult_F_Z = 1
	
		if Mult_F_Z * cutFeed > cutFeedMax:
			cutFeed = cutFeedMax
		else:
			cutFeed = cutFeed*Mult_F_Z

		block.append(CNC.zsafe()) 			#<<< Move rapid Z axis to the safe height in Stock Material

#		 Move rapid to X and Y coordinate
		if helicalCut == "Helical Cut" or helicalCut == "Internal Right Thread" or helicalCut == "Internal Left Thread":
			if entry == "Center":
				block.append(CNC.grapid(x,y))
			else:
				block.append(CNC.grapid(x-Radio+clearance ,y))

		if helicalCut == "External Right Thread" or helicalCut == "External Left Thread":
			if entry == "Center":
				clearance = 0.0
			block.append(CNC.grapid(x-Radio-clearance ,y))

		#cutFeed = int(cutFeed)
		block.append(CNC.fmt("f",cutFeed))	#<<< Set cut feed
	#	block.append(CNC.gline(x,y)
	#    while (z < 1):
		block.append(CNC.zenter(z))
		block.append(CNC.gline(x-Radio,y))
	#	cutFeed = int((CNC.vars["cutfeed"]	+ CNC.vars["cutfeedz"])/2)	#<<< Get cut feed for the current material

		#cutFeed = int(cutFeed)
		block.append(CNC.fmt("F",cutFeed))	#<<< Set cut feed
		

#-----------------------------------------------------------------------------------------------------
	#	Uncomment for first flat pass
		if helicalCut == "Helical Cut":
			block.append(CNC.gcode(turn, [("X",x-Radio),("Y",y),("Z", z),("I",Radio), ("J",0)]))
#-----------------------------------------------------------------------------------------------------
		if (z < Depth):
			pitch = -pitch

			while ((z-pitch) < Depth) :
				z = z-pitch
				block.append(CNC.gcode(turn, [("X",x-Radio),("Y",y),("Z", z),("I",Radio), ("J",0)]))

		else:
			while ((z-pitch) >= Depth) :
				z = z-pitch
				block.append(CNC.gcode(turn, [("X",x-Radio),("Y",y),("Z", z),("I",Radio), ("J",0)]))

		#Target Level
		if entry == "Center":
			clearanceExit = 0.0	
		clearance = clearanceExit
		alpha= round(Depth / pitch, 4 ) - round(Depth / pitch, 0)
		alpha = alpha * 2*pi 
		Radiox = Radio * cos(alpha)
		Radioy = Radio * sin(alpha)
		xsi = Radiox - clearance* cos(alpha)
		ysi =Radioy - clearance* sin(alpha)
		xse = Radiox + clearance* cos(alpha)
		yse =Radioy + clearance* sin(alpha)
		z = Depth



		if helicalCut == "Helical Cut":
			block.append(CNC.gcode(turn, [("X",x-Radio),("Y",y),("Z", z),("I",Radio), ("J",0)]))
			#Last flat pass
			block.append(CNC.gcode(turn, [("X",x-Radio),("Y",y),("Z", z),("I",Radio), ("J",0)]))
		elif helicalCut == 	"Internal Right Thread" or helicalCut == "External Right Thread":
			block.append(CNC.gcode(turn, [("X",x-Radiox),("Y",y-Radioy),("Z", z),("I",Radio), ("J",0)]))

		elif helicalCut == 	"Internal Left Thread" or helicalCut ==	"External Left Thread":
			block.append(CNC.gcode(turn, [("X",x-Radiox),("Y",y+Radioy),("Z", z),("I",Radio), ("J",0)]))

		# Exit clearance 
		if helicalCut == "Internal Right Thread":
			block.append(CNC.gline(x-xsi,y-ysi))
		elif helicalCut == "Internal Left Thread":
			block.append(CNC.gline(x-xsi,y+ysi))
		if helicalCut == "External Right Thread":
			block.append(CNC.gline(x-xse,y-yse))
		elif helicalCut == "External Left Thread":
			block.append(CNC.gline(x-xse,y+yse))

		# Return to Z Safe
		if returnToSafeZ == 1: 
			if helicalCut == "Helical Cut" or helicalCut == "Internal Right Thread" or helicalCut == "Internal Left Thread":
				if entry == "Center":
					block.append(CNC.gline(x,y))
			block.append(CNC.zsafe())

		blocks.append(block)
		active = app.activeBlock()
		app.gcode.insBlocks(active, blocks, "Helical_Descent inserted")	#<<< insert blocks over active block in the editor
		app.refresh()												#<<< refresh editor
		app.setStatus(_("Generated: Helical_Descent Result"))				#<<< feed back result
Esempio n. 29
0
    def execute(self, app):
        try:
            from PIL import Image
        except:
            app.setStatus(
                _("Sketch abort: This plugin requires PIL/Pillow to read image data"
                  ))
            return

        n = self["name"]
        if not n or n == "default": n = "Sketch"

        #Calc desired size
        grundgy = self["Grundgy"]
        maxSize = self["MaxSize"]
        squiggleTotal = self["SquiggleTotal"]
        squiggleLength = self["SquiggleLength"]
        depth = self["Depth"]
        drawBorder = self["DrawBorder"]
        channel = self["Channel"]
        casual = self["Casual"]
        fading = self["Fading"]
        max_light = self["Max_light"]
        repetition = self["Repetition"]

        radius = 1
        if grundgy == "Low":
            radius = 2
        elif grundgy == "Medium":
            radius = 3
        elif grundgy == "High":
            radius = 6
        elif grundgy == "Very High":
            radius = 9

        #Check parameters
        if maxSize < 1:
            app.setStatus(_("Sketch abort: Too small to draw anything!"))
            return

        if max_light > 256:
            app.setStatus(
                _("The maximum illumination shouldn't be more than 250!"))
            return

        if squiggleTotal < 1:
            app.setStatus(
                _("Sketch abort: Please let me draw at least 1 squiggle"))
            return

        if squiggleLength <= 0:
            app.setStatus(_("Sketch abort: Squiggle Length must be > 0"))
            return

        fileName = self["File"]
        try:
            img = Image.open(fileName)
        except:
            app.setStatus(_("Sketch abort: Can't read image file"))
            return

        #Create a scaled image to work faster with big image and better with small ones
        iWidth, iHeight = img.size
        resampleRatio = 800.0 / iHeight
        img = img.resize(
            (int(iWidth * resampleRatio), int(iHeight * resampleRatio)),
            Image.ANTIALIAS)
        if channel == 'Blue':
            img = img.convert('RGB')
            img = img.split()[0]
        elif channel == 'Green':
            img = img.convert('RGB')
            img = img.split()[1]
        elif channel == 'Red':
            img = img.convert('RGB')
            img = img.split()[2]
        else:
            img = img.convert('L')  #to calculate luminance

        img = img.transpose(Image.FLIP_TOP_BOTTOM)  #ouput correct image
        pix = img.load()
        #Get image size
        self.imgWidth, self.imgHeight = img.size
        self.ratio = 1
        if (iWidth > iHeight):
            self.ratio = maxSize / float(self.imgWidth)
        else:
            self.ratio = maxSize / float(self.imgHeight)

        #Init blocks
        blocks = []

        #Info block
        block = Block("Info")
        block.append(
            "(Sketch size W=%d x H=%d x distance=%d)" %
            (self.imgWidth * self.ratio, self.imgHeight * self.ratio, depth))
        block.append("(Channel = %s)" % (channel))
        blocks.append(block)

        #Border block
        block = Block("%s-border" % (self.name))
        block.enable = drawBorder
        block.append(CNC.zsafe())
        block.append(CNC.grapid(0, 0))
        block.append(CNC.zenter(depth))
        block.append(CNC.gcode(1, [("f", CNC.vars["cutfeed"])]))
        block.append(CNC.gline(self.imgWidth * self.ratio, 0))
        block.append(
            CNC.gline(self.imgWidth * self.ratio, self.imgHeight * self.ratio))
        block.append(CNC.gline(0, self.imgHeight * self.ratio))
        block.append(CNC.gline(0, 0))
        blocks.append(block)

        #choose a nice starting point
        x = self.imgWidth / 4.
        y = self.imgHeight / 4.

        #First round search in all image
        self.mostest = 256
        x, y = self.findFirst(pix, True, casual)

        #startAll = time.time()
        total_line = 0
        total_length = 0
        for c in range(squiggleTotal):
            x, y = self.findFirst(pix, False, casual)
            if pix[x, y] > max_light:
                continue
            block = Block(self.name)
            #print c,x,y
            #start = time.time()

            total_line += 1
            total_length += 1
            #move there
            block.append(CNC.zsafe())
            block.append(CNC.grapid(x * self.ratio, y * self.ratio))
            #tool down
            block.append(CNC.zenter(depth))
            #restore cut/draw feed
            block.append(CNC.gcode(1, [("f", CNC.vars["cutfeed"])]))

            #start = time.time()
            s = 0
            while (s < squiggleLength):
                x, y, distance = self.findInRange(x, y, pix, radius)
                if pix[x, y] > max_light:
                    break
                s += max(1, distance * self.ratio)  #add traveled distance
                total_length += 1
                #move there
                block.append(CNC.gline(x * self.ratio, y * self.ratio))
                self.fadePixel(
                    x, y, pix, fading,
                    repetition)  #adjustbrightness int the bright map
            #tool up
            #print 'Squiggle: %f' % (time.time() - start)
            #Gcode Zsafe
            block.append(CNC.zsafe())
            blocks.append(block)
        active = app.activeBlock()
        app.gcode.insBlocks(active, blocks, "Sketch")
        app.refresh()
        app.setStatus(
            _("Generated Sketch size W=%d x H=%d x distance=%d, Total line:%i, Total length:%d"
              ) % (self.imgWidth * self.ratio, self.imgHeight * self.ratio,
                   depth, total_line, total_length))
Esempio n. 30
0
def pocket(self, app, end_depth, mem_0, mem_1):
    """create GCode for a pocket"""
    x_start = min(OCV.WK_mems[mem_0][0], OCV.WK_mems[mem_1][0])
    y_start = min(OCV.WK_mems[mem_0][1], OCV.WK_mems[mem_1][1])

    x_end = max(OCV.WK_mems[mem_0][0], OCV.WK_mems[mem_1][0])
    y_end = max(OCV.WK_mems[mem_0][1], OCV.WK_mems[mem_1][1])

    z_start = OCV.WK_mems[mem_1][2]

    tool_dia = OCV.CD['diameter']
    tool_rad = tool_dia / 2.

    xy_stepover = tool_dia * OCV.CD['stepover'] / 100.0

    z_stepover = OCV.CD['stepz']

    # avoid infinite while loop
    if z_stepover == 0:
        z_stepover = 0.001

    msg = ("Pocket Cut Operation: \n",
           "Start: \n\n{0}\n\n".format(OCV.showC(x_start, y_start, z_start)),
           "End: \n\n{0}\n\n".format(OCV.showC(x_end, y_end, end_depth)),
           "Tool diameter: {0:.{1}f} \n\n".format(tool_dia, OCV.digits),
           "StepDown: {0:.{1}f} \n\n".format(z_stepover, OCV.digits),
           "StepOver: {0:.{1}f} \n\n".format(xy_stepover, OCV.digits))

    retval = tkMessageBox.askokcancel("Pocket Cut", "".join(msg))

    if retval is False:
        return

    # Set the Initialization file
    blocks = []
    block = Block("Init")
    # Get the current WCS as the mem are related to it
    block.append(OCV.CD['WCS'])
    blocks.append(block)

    block = Block("Pocket")
    block.append("(Pocket)")
    block.append("(Start: {0})".format(OCV.gcodeCC(x_start, y_start, z_start)))
    block.append("(End: {0})".format(OCV.gcodeCC(x_end, y_end, end_depth)))
    block.append("(StepDown: {0:.{1}f} )".format(z_stepover, OCV.digits))
    block.append("(StepOver: {0:.{1}f} )".format(xy_stepover, OCV.digits))
    block.append("(Tool diameter = {0:.{1}f})".format(tool_dia, OCV.digits))

    # Move safe to first point
    block.append(CNC.zsafe())
    block.append(CNC.grapid(x_start, y_start))

    # Init Depth

    f_width = x_end - x_start
    f_heigth = y_end - y_start

    cut_dir = "Conventional"

    x_start_pocket = x_start + tool_rad
    y_start_pocket = y_start + tool_rad

    # Calc space to work with/without border cut
    travel_width = f_width - tool_dia
    travel_height = f_heigth - tool_dia

    if travel_width < tool_rad or travel_height < tool_rad:
        msg = "(Pocket aborted: Pocket area is too small for this End Mill.)"
        retval = tkMessageBox.askokcancel("Pocket Cut", msg)
        return

    # Prepare points for pocketing
    x_p = []
    y_p = []

    # Calc number of pass
    v_count = (int)(travel_height / xy_stepover)
    h_count = (int)(travel_width / xy_stepover)

    # Make them odd
    if v_count % 2 == 0:
        v_count += 1

    if h_count % 2 == 0:
        h_count += 1

    # Calc step minor of Max step
    h_stepover = travel_height / v_count
    w_stepover = travel_width / h_count

    # Start from border to center
    x_s = x_start_pocket
    y_s = y_start_pocket
    w_s = travel_width
    h_s = travel_height
    x_c = 0
    y_c = 0

    while x_c <= h_count / 2 and y_c <= v_count / 2:
        # Pocket offset points
        x_0, y_0 = rect_path(x_s, y_s, w_s, h_s)

        if cut_dir == "Conventional":
            x_0 = x_0[::-1]
            y_0 = y_0[::-1]

        x_p = x_p + x_0
        y_p = y_p + y_0
        x_s += h_stepover
        y_s += w_stepover
        h_s -= 2.0 * h_stepover
        w_s -= 2.0 * w_stepover
        x_c += 1
        y_c += 1

        # Reverse point to start from inside (less stres on the tool)
        x_p = x_p[::-1]
        y_p = y_p[::-1]

    # Move safe to first point
    block.append(CNC.zsafe())
    block.append(CNC.grapid(x_p[0], y_p[0]))

    # Init Depth corrected by z_stepover
    # for the correctness of the loop
    # the first instruction of the while loop is -= z_stepover
    # the check is done at the final depth
    curr_depth = z_start + z_stepover

    # Create GCode from points
    while True:
        curr_depth -= z_stepover

        if curr_depth < end_depth:
            curr_depth = end_depth

        block.append(CNC.zenter(curr_depth))
        block.append(CNC.gcode_string(1, [("F", OCV.CD["cutfeed"])]))

        # Pocketing
        for x_l, y_l in zip(x_p, y_p):
            block.append(CNC.gline(x_l, y_l))

        # Move to the begin in a safe way
        block.append(CNC.zsafe())
        block.append(CNC.grapid(x_p[0], y_p[0]))

        # Verify exit condition
        if curr_depth <= end_depth:
            break

    # end of the loop
    # return to z_safe
    block.append(CNC.zsafe())
    blocks.append(block)

    if blocks is not None:
        active = OCV.APP.activeBlock()

        if active == 0:
            active = 1

        OCV.APP.gcode.insBlocks(active, blocks, "Line Cut")
        OCV.APP.refresh()
        OCV.APP.setStatus(_("Line Cut: Generated line cut code"))
Esempio n. 31
0
	def execute(self, app):
		try:
			from PIL import Image
		except:
			app.setStatus(_("Sketch abort: This plugin requires PIL/Pillow to read image data"))
			return

		n = self["name"]
		if not n or n=="default": n="Sketch"

		#Calc desired size
		grundgy =self["Grundgy"]
		maxSize = self["MaxSize"]
		squiggleTotal  = self["SquiggleTotal"]
		squiggleLength = self["SquiggleLength"]
		depth = self["Depth"]
		drawBorder = self["DrawBorder"]
		channel = self["Channel"]

		radius = 1
		if grundgy == "Low":
			radius = 2
		elif grundgy == "Medium":
			radius = 3
		elif grundgy == "High":
			radius = 6
		elif grundgy == "Very High":
			radius = 9

		#Check parameters
		if maxSize < 1:
			app.setStatus(_("Sketch abort: Too small to draw anything!"))
			return

		if squiggleTotal < 1:
			app.setStatus(_("Sketch abort: Please let me draw at least 1 squiggle"))
			return
			
		if squiggleLength <= 0:
			app.setStatus(_("Sketch abort: Squiggle Length must be > 0"))
			return

		fileName = self["File"]
		try:
			img = Image.open(fileName)
		except:
			app.setStatus(_("Sketch abort: Can't read image file"))
			return

		#Create a scaled image to work faster with big image and better with small ones
		iWidth,iHeight = img.size
		resampleRatio = 800.0 / iHeight
		img = img.resize((int(iWidth *resampleRatio) ,int(iHeight * resampleRatio)), Image.ANTIALIAS)
		if channel == 'Blue':
			img = img.convert('RGB')
			img = img.split()[0]
		elif channel == 'Green':
			img = img.convert('RGB')
			img = img.split()[1]
		elif channel == 'Red':
			img = img.convert('RGB')
			img = img.split()[2]
		else:
			img = img.convert ('L') #to calculate luminance

		img = img.transpose(Image.FLIP_TOP_BOTTOM) #ouput correct image
		pix = img.load()

		#Get image size
		self.imgWidth, self.imgHeight =  img.size
		self.ratio = 1
		if (iWidth > iHeight):
			self.ratio = maxSize / float(self.imgWidth)
		else:
			self.ratio = maxSize / float(self.imgHeight)

		#Init blocks
		blocks = []

		#Border block
		block = Block("%s-border"%(self.name))
		block.enable = drawBorder
		block.append(CNC.zsafe())
		block.append(CNC.grapid(0,0))
		block.append(CNC.zenter(depth))
		block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])]))
		block.append(CNC.gline(self.imgWidth * self.ratio, 0))
		block.append(CNC.gline(self.imgWidth * self.ratio, self.imgHeight*self.ratio))
		block.append(CNC.gline(0, self.imgHeight*self.ratio))
		block.append(CNC.gline(0,0))
		blocks.append(block)

		#Draw block
		block = Block(self.name)
		block.append("(Sketch size W=%d x H=%d x distance=%d)" %
			 (self.imgWidth * self.ratio  , self.imgHeight * self.ratio  , depth))
		block.append("(Channel = %s)" %(channel))
		#choose a nice starting point
		x = self.imgWidth / 4.
		y = self.imgHeight / 4.

		#First round search in all image
		self.mostest = 256
		x,y = self.findFirst(pix, True)

		#startAll = time.time()
		for c in range(squiggleTotal):
			#print c,x,y
			#start = time.time()
			x,y = self.findFirst(pix, False)
			#print 'Find mostest: %f' % (time.time() - start)
			#move there
			block.append(CNC.zsafe())
			block.append(CNC.grapid(x*self.ratio, y*self.ratio))
			#tool down
			block.append(CNC.zenter(depth))
			#restore cut/draw feed
			block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])]))

			#start = time.time()
			s = 0
			while (s < squiggleLength):
				x,y,distance = self.findInRange(x, y, pix, radius)
				s+= max(1,distance*self.ratio)  #add traveled distance
				#move there
				block.append(CNC.gline(x*self.ratio,y*self.ratio))
				self.fadePixel(x, y, pix) #adjustbrightness int the bright map
			#tool up
			block.append(CNC.zsafe())
			#print 'Squiggle: %f' % (time.time() - start)

		#Gcode Zsafe
		block.append(CNC.zsafe())
		blocks.append(block)
		active = app.activeBlock()
		app.gcode.insBlocks(active, blocks, "Sketch")
		app.refresh()
		app.setStatus(_("Generated Sketch size W=%d x H=%d x distance=%d, Total length:%d") %
			(self.imgWidth*self.ratio  , self.imgHeight*self.ratio , depth, squiggleTotal*squiggleLength))
Esempio n. 32
0
	def trochoid(self, typesplice, A, B, oldradius, radius, oldphi,phi, cw=True):

		if self["splicesteps"] =="" or self["splicesteps"]<4:
			steps=4/(2*pi)
		else:
			steps=self["splicesteps"]/(2*pi)

		t_splice = typesplice
		block = []

		if cw:
			u = 1
			arc = "G2"
			cut_splice="G3"
		else:
			u = -1
			arc = "G3"
			cut_splice="G2"

#		phi = atan2(B[1]-A[1], B[0]-A[0])
#		step = sqrt((A[0]-B[0])**2+(A[1]-B[1])**2)

		l = self.pol2car(radius, phi+radians(90*u))
		r = self.pol2car(radius, phi+radians(-90*u))
		al = self.pol2car(oldradius, phi+radians(90*u), A)
		ar = self.pol2car(oldradius, phi+radians(-90*u), A)
		bl = self.pol2car(radius, phi+radians(90*u), B)
		br = self.pol2car(radius, phi+radians(-90*u), B)

#		prev_al = self.pol2car(oldradius, phi+radians(90*u), A)
#		prev_ar = self.pol2car(oldradius, phi+radians(-90*u), A)
#		old_l = self.pol2car(oldradius, oldphi+radians(90*u))
#		old_r = self.pol2car(oldradius, oldphi+radians(-90*u))

#		infinite radius
		inf_radius=1
#		inf_l = self.pol2car(500*radius, phi+radians(90*u))
#		inf_r = self.pol2car(500*radius, phi+radians(-90*u))
#		inf_Cl = self.pol2car(inf_radius*radius, phi+radians(-90*u), B)
#		inf_Cl= inf_Cl[0],inf_Cl[1],B[2]
#		inf_Cr = self.pol2car(inf_radius*radius, phi+radians(90*u), B)
#		inf_Cl= inf_Cr[0],inf_Cr[1],B[2]

		splice_dist=sqrt((br[0]-al[0])**2+(br[1]-al[1])**2)
		splice_radius=splice_dist/2.0



		# This schematic drawing represents naming convention
		# of points and vectors calculated in previous block
		#
		#    <--L---
		#          ---R-->
		#
		#        *   *
		#     *         *
		#    *           *
		#   BL     B     BR
		#    *           *
		#    *     ^     *
		#    *     |     *
		#    *     |     *
		#    *           *
		#   AL     A     AR
		#    *           *
		#     *         *
		#        *   *

		#TODO: improve strategies
#			block.append("g1 x"+str(al[0])+" y"+str(al[1])+" z"+str(A[2]))
#		First splice to next trochoid ========================================================
#		steps=self["splicesteps"]
#		steps = max(steps*oldradius,steps*radius)#self["splicesteps"]
#		steps = int(min(10,steps))#self["splicesteps"]
		
		block.append("(---------trochoid center x "+str(round(B[0],4))+" y "+str(round(B[1],4))+" ---------)")
		if t_splice == "came_back":
#			block.append(CNC.gline(round(A[0],5),round(A[1],5),round(B[2],5)))
			block.append(CNC.gline(round(B[0],5),round(B[1],5),round(B[2],5)))
#			block.append(arc+" x"+str(round(br[0],4))+" y"+str(round(br[1],4))+" R"+str(1.001*radius/2.0)+" z"+str(round(B[2],4))) 
			block.append(arc+" x"+str(round(br[0],4))+" y"+str(round(br[1],4))+" R"+str(self.roundup(radius/2.0,3))+" z"+str(round(B[2],4))) 
#			block.extend(self.splice_generator(steps,A,B,oldradius,radius/2.0,oldphi,phi,radians(270),radians(60),u))
#			block.append("(ppp)")
#			block.extend(self.splice_generator(steps,B,B,radius/2.0,radius,phi,phi,radians(60),radians(-90),u))

		else:
			block.append("( phi "+str(round(degrees(phi),2))+" oldphi "+str(round(degrees(oldphi),2))+" )")
			if oldphi!= phi:
				block.append("(=============== Direction changed olldhi ==================)")
			#if oldphi!=phi and t_splice!="Splices" and t_splice!="Warpedarc" and t_splice!="Circular one side rectified":
#				steps = int(15*radius)
			#	block.append("()")
			#	if t_splice!="Circular both sides rectified" :
				block.append("( Splice arch for direction change )")
	#				block.extend(self.splice_generator(A,A,oldradius,oldradius,oldphi,phi,radians(270),radians(-90),u))
	#			block.extend(self.curve_splice_generator(A,A,oldradius,oldradius,oldphi,phi,radians(270),radians(-90),u,steps))
				block.extend(self.curve_splice_generator(A,A,oldradius,oldradius,oldphi,phi,radians(270),radians(-90),u,4)) #<< steps=4
				block.append("(=============== End Direction changed ==================)")
	#				block.append("(new phi)")
	#				block.append(CNC.gline(old_ar[0],old_ar[1]))
	#				block.append(arc +" x"+str(ar[0])+" y"+str(ar[1])+" i"+str(-old_r[0])+" j"+str(-old_r[1])) #<<in adaptativee presents problems of location of the center in change of angle
	#				block.append(arc +" x"+str(prev_ar[0])+" y"+str(prev_ar[1])+" i"+str(-old_r[0])+" j"+str(-old_r[1])) #<<in adaptativee presents problems of location of the center in change of angle
	#				block.append(arc +" x"+str(prev_al[0])+" y"+str(prev_al[1])+" R"+str(oldradius))
	#				block.append(arc+" x"+str(prev_al[0])+" y"+str(prev_al[1])+" i"+str(-old_l[0])+" j"+str(-old_l[1])+" )")
	#				block.append(arc +" x"+str(prev_ar[0])+" y"+str(prev_ar[1])+" R"+str(oldradius))
			#	else:
			#		block.append("( Splice arch for direction change )")
	#				block.append(arc +" x"+str(al[0])+" y"+str(al[1])+" i"+str(old_r[0])+" j"+str(old_r[1]))
			#		block.append(arc +" x"+str(round(ar[0],4))+" y"+str(round(ar[1],4))+" R"+str(self.roundup(oldradius,3)))
			#		block.append(arc +" x"+str(round(al[0],4))+" y"+str(round(al[1],4))+" R"+str(self.roundup(oldradius,3)))
			#	block.append("()")

			if t_splice == "Splices":
#				block.append("(Soft steps "+str(steps)+" )")
				block.extend(self.splice_generator(A,B,oldradius,radius,oldphi,phi,radians(-90),radians(90),u,steps))

			elif t_splice == "Circular one side rectified":
	#			block.append(arc+" x"+str(al[0])+" y"+str(al[1])+" i"+str(old_l[0])+" j"+str(old_l[1])+" z"+str(round(B[2],5)))#<<in adaptativee presents problems of location of the center in change of angle
				block.append(arc+" x"+str(round(al[0],4))+" y"+str(round(al[1],4))+" R"+str(self.roundup(oldradius,3))+" z"+str(round(B[2],5)))
				block.append("g1 x"+str(round(bl[0],4))+" y"+str(round(bl[1],4))+" z"+str(round(B[2],4)))

			elif t_splice == "Circular both sides rectified" :
				block.append("g1 x"+str(round(bl[0],4))+" y"+str(round(bl[1],4))+" z"+str(round(B[2],4)))

			elif t_splice == "Straight":
				block.append("g1 x"+str(round(bl[0],4))+" y"+str(round(bl[1],4))+" z"+str(round(B[2],4)))

			elif t_splice == "Warpedarc":
				warped_radius=(sqrt((ar[0]-bl[0])**2+(ar[1]-bl[1])**2))/2.0
				block.append("(Warpedarc)")
				block.append("(control previous position arx "+str(round(ar[0],4))+" ary "+str(round(ar[1],4))+" R "+ str(warped_radius)+" )")
				block.append(arc+" x"+str(round(bl[0],4))+" y"+str(round(bl[1],4))+" R"+str(self.roundup(warped_radius,3))+" z"+str(round(B[2],5)))

			elif t_splice == "Straight on side rectified":			
				block.append("g1 x"+str(round(al[0],4))+" y"+str(round(al[1],4)))
				block.append("g1 x"+str(round(bl[0],4))+" y"+str(round(bl[1],4))+" z"+str(round(B[2],4)))

			elif t_splice == "Cut":
				block.append("g1 x"+str(round(ar[0],4))+" y"+str(round(ar[1],4)))
				block.append(cut_splice+"x"+str(round(bl[0],4))+" y"+str(round(bl[1],4))+"R"+str(self.roundup(splice_radius,3))+" z"+str(round(B[2],4)))

	#		========================================================================================================
		#	cut
#			block.append(arc+" x"+str(br[0])+" y"+str(br[1])+" i"+str(r[0])+" j"+str(r[1])+" z"+str(round(B[2],5)))
			block.append("(cuting)") 
			block.append(arc+" x"+str(round(br[0],4))+" y"+str(round(br[1],4))+" R"+str(self.roundup(radius,3))+" z"+str(round(B[2],4))) 
		#	block.append("(cut)")
		#	========================================================================================================
			if t_splice== "Circular both sides rectified":
				block.append("g1 x"+str(round(ar[0],4))+" y"+str(round(ar[1],4))+" z"+str(round(A[2],4)))
	#			block.append(arc+" x"+str(al[0])+" y"+str(al[1])+" i"+str(old_l[0])+" j"+str(old_l[1])+" z"+str(round(A[2],5)))
				block.append(arc+" x"+str(round(al[0],4))+" y"+str(round(al[1],4))+" R"+str(self.roundup(oldradius,3))+" z"+str(round(A[2],4))) #<<in adaptativee presents problems of location of the center in change of angle
				block.append("g1 x"+str(round(bl[0],4))+" y"+str(round(bl[1],4))+" z"+str(round(B[2],4)))

		return block
Esempio n. 33
0
File: gear.py Progetto: multpix/bCNC
	def calc(self, N, phi, Pc):
		N = abs(N)
		# Pitch Circle
		D = N * Pc / math.pi
		R = D / 2.0

		# Diametrical pitch
		Pd = N / D

		# Base Circle
		Db = D * math.cos(phi)
		Rb = Db / 2.0

		# Addendum
		a = 1.0 / Pd

		# Outside Circle
		Ro = R + a
		Do = 2.0 * Ro

		# Tooth thickness
		T = math.pi*D / (2*N)

		# undercut?
		U = 2.0 / (math.sin(phi) * (math.sin(phi)))
		needs_undercut = N < U
		# sys.stderr.write("N:%s R:%s Rb:%s\n" % (N,R,Rb))

		# Clearance
		c = 0.0
		# Dedendum
		b = a + c

		# Root Circle
		Rr = R - b
		Dr = 2.0*Rr

		two_pi = 2.0*math.pi
		half_thick_angle = two_pi / (4.0*N)
		pitch_to_base_angle = self.involute_intersect_angle(Rb, R)
		pitch_to_outer_angle = self.involute_intersect_angle(Rb, Ro) # pitch_to_base_angle

		points = []
		for x in range(1,N+1):
			c = x * two_pi / N

			# angles
			pitch1 = c - half_thick_angle
			base1  = pitch1 - pitch_to_base_angle
			outer1 = pitch1 + pitch_to_outer_angle

			pitch2 = c + half_thick_angle
			base2  = pitch2 + pitch_to_base_angle
			outer2 = pitch2 - pitch_to_outer_angle

			# points
			b1 = self.point_on_circle(Rb, base1)
			p1 = self.point_on_circle(R,  pitch1)
			o1 = self.point_on_circle(Ro, outer1)
			o2 = self.point_on_circle(Ro, outer2)
			p2 = self.point_on_circle(R,  pitch2)
			b2 = self.point_on_circle(Rb, base2)

			if Rr >= Rb:
				pitch_to_root_angle = pitch_to_base_angle - self.involute_intersect_angle(Rb, Rr)
				root1 = pitch1 - pitch_to_root_angle
				root2 = pitch2 + pitch_to_root_angle
				r1 = self.point_on_circle(Rr, root1)
				r2 = self.point_on_circle(Rr, root2)

				points.append(r1)
				points.append(p1)
				points.append(o1)
				points.append(o2)
				points.append(p2)
				points.append(r2)
			else:
				r1 = self.point_on_circle(Rr, base1)
				r2 = self.point_on_circle(Rr, base2)
				points.append(r1)
				points.append(b1)
				points.append(p1)
				points.append(o1)
				points.append(o2)
				points.append(p2)
				points.append(b2)
				points.append(r2)

		first = points[0]
		del points[0]

		blocks = []
		block = Block(self.name)
		blocks.append(block)

		block.append(CNC.grapid(first.x(), first.y()))
		block.append(CNC.zenter(0.0))
		#print first.x(), first.y()
		for v in points:
			block.append(CNC.gline(v.x(), v.y()))
			#print v.x(), v.y()
		#print first.x(), first.y()
		block.append(CNC.gline(first.x(), first.y()))
		block.append(CNC.zsafe())

		#block = Block("%s-center"%(self.name))
		block = Block("%s-basecircle"%(self.name))
		block.enable = False
		block.append(CNC.grapid(Db/2, 0.))
		block.append(CNC.zenter(0.0))
		block.append(CNC.garc(CW, Db/2, 0., i=-Db/2))
		block.append(CNC.zsafe())
		blocks.append(block)
		return blocks
Esempio n. 34
0
    def execute(self, app):
        try:
            from PIL import Image
        except:
            app.setStatus(
                _("Pyrograph abort: This plugin requires PIL/Pillow"))
            return

        n = self["name"]
        if not n or n == "default": n = "Pyrograph"

        #Calc desired size
        toolSize = self.fromMm("ToolSize")
        maxSize = self.fromMm("MaxSize")
        feedMin = self["FeedMin"]
        feedMax = self["FeedMax"]
        depth = self.fromMm("Depth")
        direction = self["Direction"]
        drawBorder = self["DrawBorder"]

        #Check parameters
        if direction is "":
            app.setStatus(_("Pyrograph abort: please define a scan Direction"))
            return

        if toolSize <= 0:
            app.setStatus(_("Pyrograph abort: Tool Size must be > 0"))
            return

        if feedMin <= 0 or feedMax <= 0:
            app.setStatus(
                _("Pyrograph abort: Please check feed rate parameters"))
            return

        #divisions
        divisions = maxSize / toolSize

        fileName = self["File"]
        try:
            img = Image.open(fileName)
            img = img.convert(
                'RGB')  #be sure to have color to calculate luminance
        except:
            app.setStatus(_("Pyrograph abort: Can't read image file"))
            return

        iWidth, iHeight = img.size
        newWidth = iWidth
        newHeight = iHeight

        ratio = 1
        if (iWidth > iHeight):
            ratio = float(iWidth) / float(iHeight)
            newWidth = int(divisions)
            newHeight = int(divisions / ratio)
        else:
            ratio = float(iHeight) / float(iWidth)
            newWidth = int(divisions / ratio)
            newHeight = int(divisions)

        #Create a thumbnail image to work faster
        img.thumbnail((newWidth, newHeight), Image.ANTIALIAS)
        newWidth, newHeight = img.size
        #img.save("thumb.png")
        pixels = list(img.getdata())

        #Extract luminance
        gMap = []
        for x in range(0, newWidth):
            gRow = []
            for y in range(0, newHeight):
                R, G, B = pixels[(y * newWidth) + x]
                L = (0.299 * R + 0.587 * G + 0.114 * B
                     )  #Luminance (Rec. 601 standard)
                gRow.append(L)
            gMap.append(gRow)

        #Init blocks
        blocks = []
        block = Block(self.name)
        block.append("(Pyrograph W=%g x H=%g x D=%g)" %
                     (newWidth * toolSize, newHeight * toolSize, depth))

        #Create points for vertical scan
        xH = []
        yH = []
        fH = []
        if (direction == "Vertical" or direction == "Both"):
            r = range(0, newHeight)
            for x in range(0, newWidth):
                r = r[::-1]
                fPrec = -1
                for y in r:
                    f = int(feedMin +
                            ((feedMax - feedMin) * gMap[x][y] / 255.0))
                    if (f != fPrec or y == 0 or y == newHeight - 1):
                        xH.append(x * toolSize)
                        yH.append((newHeight - y) * toolSize)
                        fH.append(f)
                    fPrec = f

        #Create points for horizontal scan
        xV = []
        yV = []
        fV = []
        if (direction == "Horizontal" or direction == "Both"):
            r = range(0, newWidth)
            for y in reversed(range(0, newHeight)):
                fPrec = -1
                for x in r:
                    f = int(feedMin +
                            ((feedMax - feedMin) * gMap[x][y] / 255.0))
                    if (f != fPrec or x == 0 or x == newWidth - 1):
                        xV.append(x * toolSize)
                        yV.append((newHeight - y) * toolSize)
                        fV.append(f)
                    fPrec = f
                r = r[::-1]

        #Gcode Horizontal
        if (len(xH) > 1 and len(yH) > 1):
            block.append(CNC.zsafe())
            block.append(CNC.grapid(xH[0], yH[0]))
            block.append(CNC.zenter(depth))
            for x, y, f in zip(xH, yH, fH):
                v = (x, y, depth)
                block.append(CNC.glinev(1, v, f))

        #Gcode Vertical
        if (len(xV) > 1 and len(yV) > 1):
            block.append(CNC.zsafe())
            block.append(CNC.grapid(xV[0], yV[0]))
            block.append(CNC.zenter(depth))
            for x, y, f in zip(xV, yV, fV):
                v = (x, y, depth)
                block.append(CNC.glinev(1, v, f))

        #Draw Border if required
        if drawBorder:
            block.append(CNC.zsafe())
            block.append(CNC.grapid(0, 0))
            block.append(CNC.zenter(depth))
            block.append(CNC.gcode(1, [("f", feedMin)]))
            block.append(CNC.gline(newWidth * toolSize - toolSize, 0))
            block.append(
                CNC.gline(newWidth * toolSize - toolSize,
                          newHeight * toolSize))
            block.append(CNC.gline(0, newHeight * toolSize))
            block.append(CNC.gline(0, 0))

        #Gcode Zsafe
        block.append(CNC.zsafe())

        blocks.append(block)
        active = app.activeBlock()
        if active == 0: active = 1
        app.gcode.insBlocks(active, blocks, "Pyrograph")
        app.refresh()
        app.setStatus(
            _("Generated Pyrograph W=%g x H=%g x D=%g") %
            (newWidth * toolSize, newHeight * toolSize, depth))
Esempio n. 35
0
    def execute(self, app):
        name = self['name']

        if not name or name == 'default':
            name = 'Function'

        # Initialize blocks that will contain our gCode
        blocks = []
        block = Block(name)

        #Variable definitions
        formula = self['form']
        res = self['res']  # X resolution
        ran = [self['ranX'],
               self['ranY']]  # Range of X,Y, from -10, to 10 range is 20
        cent = [
            self['centX'], self['centY']
        ]  # Coordinates X,Y of the center from bottom left of the coordinate system
        dim = [self['dimX'], self['dimY']]  # Real dimensions in gcode units
        spacX = self['spacX']  # Spacing of X axis lines
        spacY = self['spacY']  # Spacing of Y axis lines
        lin = self['lin']  # Small value - length of a line in gcode units
        draw = self['draw']  # Draw the coordinate system

        block.append("(Generated with a script by kswiorek)\n")
        block.append("(Equation: " + formula + ")\n")
        block.append("(Resolution: " + str(res) + ")\n")
        block.append("(Range: " + str(ran) + ")\n")
        block.append("(Center: " + str(cent) + ")\n")
        block.append("(Dimensions: " + str(dim) + ")\n")
        block.append("(SpacingXY: " + str(spacX) + ", " + str(spacY) + ")\n")

        def mapc(var, axis):  #Map coordinate systems
            return (var * (dim[axis] / ran[axis]))

        #Define coordinate system mins and maxes
        minX = -cent[0]
        maxX = ran[0] - cent[0]

        minY = -cent[1]
        maxY = ran[1] - cent[1]

        #Define domain and codomain
        X = []
        Y = []

        e_old = ""  #Store old exception to comapre

        #Calculate values for arguments with a resolution
        for i in range(0, int(ran[0] / res +
                              1)):  #Complaints about values beeing floats
            x = i * res + minX  #Iterate x
            X.append(x)
            try:
                Y.append(eval(formula))

            except Exception as exc:  #Append None, not to loose sync with X
                Y.append(None)
                e = str(exc)
                if e != e_old:  #If there is a different exception - display it
                    print("Warning: " + str(e))
                    app.setStatus(_("Warning: " + str(e)))
                    e_old = e

        raised = True  # Z axis is raised at start

        #Clip values out of bounds, replace with None, not to loose sync with X
        for i, item in enumerate(Y):
            y = Y[i]
            if not y is None and (y < minY or y > maxY):
                Y[i] = None

        #Y without "None", min() and max() can't compare them
        Ynn = []  #Y no Nones
        for i, item in enumerate(Y):
            if not Y[i] is None:
                Ynn.append(Y[i])

        block.append(CNC.gcode(1, [("f", CNC.vars["cutfeed"])]))  #Set feedrate

        if draw:  #If the user selected to draw the coordinate system
            #X axis
            block.append(CNC.grapid(z=3))
            block.append(CNC.grapid(0, mapc(cent[1],
                                            1)))  #1st point of X axis line
            block.append(CNC.grapid(z=0))

            block.append(CNC.gline(dim[0] + lin * 1.2, mapc(
                cent[1], 1)))  #End of X axis line + a bit more for the arrow

            block.append(
                CNC.gline(dim[0] - lin / 2,
                          mapc(cent[1], 1) -
                          lin / 2))  #bottom part of the arrow

            block.append(CNC.grapid(z=3))
            block.append(CNC.grapid(dim[0] + lin * 1.2, mapc(cent[1], 1),
                                    0))  #End of X axis line
            block.append(CNC.grapid(z=0))

            block.append(
                CNC.gline(dim[0] - lin / 2,
                          mapc(cent[1], 1) + lin / 2))  #top part of the arrow
            block.append(CNC.grapid(z=3))

            #Y axis, just inverted x with y
            block.append(CNC.grapid(z=3))
            block.append(CNC.grapid(mapc(cent[0], 0),
                                    0))  #1st point of Y axis line
            block.append(CNC.grapid(z=0))

            block.append(CNC.gline(
                mapc(cent[0], 0), dim[1] +
                lin * 1.2))  #End of Y axis line + a bit more for the arrow

            block.append(
                CNC.gline(mapc(cent[0], 0) - lin / 2,
                          dim[1] - lin / 2))  #left part of the arrow

            block.append(CNC.grapid(z=3))
            block.append(CNC.grapid(mapc(cent[0], 0),
                                    dim[1] + lin * 1.2))  #End of Y axis line
            block.append(CNC.grapid(z=0))

            block.append(
                CNC.gline(mapc(cent[0], 0) + lin / 2,
                          dim[1] - lin / 2))  #right part of the arrow
            block.append(CNC.grapid(z=3))

            #X axis number lines
            i = 0
            while i < ran[0] - cent[0]:  #While i is on the left of the arrow
                i += spacX  #Add line spacing

                #Draw lines right of the center
                block.append(
                    CNC.grapid(mapc(i + cent[0], 0),
                               mapc(cent[1], 1) + lin / 2))
                block.append(CNC.grapid(z=0))
                block.append(
                    CNC.gline(mapc(i + cent[0], 0),
                              mapc(cent[1], 1) - lin / 2))
                block.append(CNC.grapid(z=3))

            i = 0
            while i > -cent[
                    0]:  #While i is lower than center coordinate, inverted for easier math
                i -= spacX  #Add line spacing

                #Draw lines left of the center
                block.append(
                    CNC.grapid(mapc(i + cent[0], 0),
                               mapc(cent[1], 1) + lin / 2))
                block.append(CNC.grapid(z=0))
                block.append(
                    CNC.gline(mapc(i + cent[0], 0),
                              mapc(cent[1], 1) - lin / 2))
                block.append(CNC.grapid(z=3))

            #Y axis number lines
            i = 0
            while i < ran[1] - cent[
                    1]:  #While i is between the center and the arrow
                i += spacX  #Add line spacing

                #Draw lines top of the center (everything just inverted)
                block.append(
                    CNC.grapid(
                        mapc(cent[0], 0) + lin / 2, mapc(i + cent[1], 1)))
                block.append(CNC.grapid(z=0))
                block.append(
                    CNC.gline(
                        mapc(cent[0], 0) - lin / 2, mapc(i + cent[1], 1)))
                block.append(CNC.grapid(z=3))

            i = 0
            while i > -1 * cent[1]:
                i -= spacX  #Add line spacing

                #Draw lines bottom of the center
                block.append(
                    CNC.grapid(
                        mapc(cent[0], 0) + lin / 2, mapc(i + cent[1], 1)))
                block.append(CNC.grapid(z=0))
                block.append(
                    CNC.gline(
                        mapc(cent[0], 0) - lin / 2, mapc(i + cent[1], 1)))
                block.append(CNC.grapid(z=3))

            raised = True  #Z was raised

        #Draw graph
        for i, item in enumerate(Y):
            if not Y[i] is None:
                x = mapc(X[i] + cent[0], 0)  #Take an argument
                y = mapc(Y[i] + cent[1], 1)  #Take a value
            else:
                y = Y[i]  #only for tne None checks next

            if y is None and not raised:  #If a None "period" just started raise Z
                raised = True
                block.append(CNC.grapid(z=3))
            elif not y is None and raised:  #If Z was raised and the None "period" ended move to new coordinates
                block.append(CNC.grapid(round(x, 2), round(y, 2)))
                block.append(CNC.grapid(z=0))  #Lower Z
                raised = False
            elif not y is None and not raised:  #Nothing to do with Nones? Just draw
                block.append(CNC.gline(round(x, 2), round(y, 2)))

        block.append(CNC.grapid(z=3))  #Raise on the end

        blocks.append(block)
        active = app.activeBlock()
        app.gcode.insBlocks(active, blocks, 'Function inserted'
                            )  #insert blocks over active block in the editor
        app.refresh()  #refresh editor
        app.setStatus(_('Generated function graph'))  #feed back result
        print()
Esempio n. 36
0
	def execute(self, app):
		try:
			from PIL import Image
		except:
			app.setStatus(_("Pyrograph abort: This plugin requires PIL/Pillow"))
			return

		n = self["name"]
		if not n or n=="default": n="Pyrograph"

		#Calc desired size
		toolSize = self.fromMm("ToolSize")
		maxSize = self.fromMm("MaxSize")
		feedMin = self["FeedMin"]
		feedMax = self["FeedMax"]
		depth = self.fromMm("Depth")
		direction = self["Direction"]
		drawBorder = self["DrawBorder"]

		#Check parameters
		if direction is "":
			app.setStatus(_("Pyrograph abort: please define a scan Direction"))
			return

		if toolSize <=0:
			app.setStatus(_("Pyrograph abort: Tool Size must be > 0"))
			return

		if feedMin <=0 or feedMax <=0 :
			app.setStatus(_("Pyrograph abort: Please check feed rate parameters"))
			return

		#divisions
		divisions = maxSize / toolSize

		fileName = self["File"]
		try:
			img = Image.open(fileName)
			img = img.convert ('RGB') #be sure to have color to calculate luminance
		except:
			app.setStatus(_("Pyrograph abort: Can't read image file"))
			return

		iWidth,iHeight =  img.size
		newWidth = iWidth
		newHeight = iHeight

		ratio = 1
		if (iWidth > iHeight):
			ratio = float(iWidth) / float(iHeight)
			newWidth = int(divisions)
			newHeight = int(divisions / ratio)
		else:
			ratio = float(iHeight) / float(iWidth)
			newWidth = int(divisions / ratio)
			newHeight = int(divisions)

		#Create a thumbnail image to work faster
		img.thumbnail((newWidth,newHeight), Image.ANTIALIAS)
		newWidth,newHeight =  img.size
		#img.save("thumb.png")
		pixels = list(img.getdata())

		#Extract luminance
		gMap = []
		for x in range(0,newWidth):
			gRow = []
			for y in range(0,newHeight):
				R,G,B = pixels[(y * newWidth) + x ]
				L = (0.299*R + 0.587*G + 0.114*B) #Luminance (Rec. 601 standard)
				gRow.append(L)
			gMap.append(gRow)

		#Init blocks
		blocks = []
		block = Block(self.name)
		block.append("(Pyrograph W=%g x H=%g x D=%g)" %
		(newWidth * toolSize , newHeight * toolSize , depth))

		#Create points for vertical scan
		xH = []
		yH = []
		fH = []
		if (direction=="Vertical" or direction=="Both"):
			r = range(0,newHeight)
			for x in range(0,newWidth):
				r = r[::-1]
				fPrec = -1
				for y in r:
					f = int(feedMin + ((feedMax - feedMin) * gMap[x][y] / 255.0))
					if(f != fPrec or y==0 or  y==newHeight-1):
						xH.append(x * toolSize)
						yH.append((newHeight-y) * toolSize)
						fH.append(f)
					fPrec = f

		#Create points for horizontal scan
		xV = []
		yV = []
		fV = []
		if (direction=="Horizontal" or direction=="Both"):
			r = range(0,newWidth)
			for y in reversed(range(0,newHeight)):
				fPrec = -1
				for x in r:
					f = int(feedMin + ((feedMax - feedMin) * gMap[x][y] / 255.0))
					if(f != fPrec or x==0 or x==newWidth-1):
						xV.append(x * toolSize)
						yV.append((newHeight-y) * toolSize)
						fV.append(f)
					fPrec = f
				r = r[::-1]

		#Gcode Horizontal
		if (len(xH)>1 and len(yH)>1):
			block.append(CNC.zsafe())
			block.append(CNC.grapid(xH[0],yH[0]))
			block.append(CNC.zenter(depth))
			for x,y,f in zip(xH,yH,fH):
					v = (x,y,depth)
					block.append(CNC.glinev(1,v,f))

		#Gcode Vertical
		if (len(xV)>1 and len(yV)>1):
			block.append(CNC.zsafe())
			block.append(CNC.grapid(xV[0],yV[0]))
			block.append(CNC.zenter(depth))
			for x,y,f in zip(xV,yV,fV):
					v = (x,y,depth)
					block.append(CNC.glinev(1,v,f))

		#Draw Border if required
		if drawBorder:
			block.append(CNC.zsafe())
			block.append(CNC.grapid(0,0))
			block.append(CNC.zenter(depth))
			block.append(CNC.gcode(1, [("f",feedMin)]))
			block.append(CNC.gline(newWidth * toolSize - toolSize,0))
			block.append(CNC.gline(newWidth * toolSize - toolSize ,newHeight* toolSize))
			block.append(CNC.gline(0,newHeight* toolSize ))
			block.append(CNC.gline(0,0))

		#Gcode Zsafe
		block.append(CNC.zsafe())

		blocks.append(block)
		active = app.activeBlock()
		if active==0: active=1
		app.gcode.insBlocks(active, blocks, "Pyrograph")
		app.refresh()
		app.setStatus(_("Generated Pyrograph W=%g x H=%g x D=%g") %
		(newWidth * toolSize , newHeight * toolSize , depth))
Esempio n. 37
0
	def make(self,app, XStart=0.0, YStart=0.0, ZStart=30., AlignAxis="Y", \
			RotAxis="A", StockLeng=20, ReduceDepth=-1, PassDepth=1, \
			Stepover=1, ZApproach=35, SpiralType="Spiral", CutBoth="True", LiftPass="******"):

		#GCode Blocks
		blocks = []
		
		# Load tool and material settings
		toolDiam = CNC.vars['diameter']
		toolRadius = toolDiam / 2.

		#Calc tool diameter with Maximum Step Over allowed
		StepOverInUnitMax = toolDiam * CNC.vars['stepover'] / 100.0		

		#Check parameters
		if RotAxis == "":
			app.setStatus(_("Spiral abort: Rotary Axis is undefined"))
			return

		if SpiralType == "":
			app.setStatus(_("Spiral abort: Spiral Type is undefined"))
			return

		if ZApproach <= ZStart :
			app.setStatus(_("Spiral abort: Approach height must be greater than Z Start"))
			return

		if ReduceDepth > 0 :
			app.setStatus(_("Spiral abort: Depth Reduction must be negative"))
			return

		if Stepover > StepOverInUnitMax and SpiralType == "Spiral":  #if Type is Lines then stepover is degrees not mm
			app.setStatus(_("Spiral abort: Step Over exceeds tool limits"))
			return 
		elif Stepover > StepOverInUnitMax and SpiralType == "Lines":  # This could cause a tool crash, but could also be used to make faceted shapes.
			dr=tkMessageBox.askyesno("Crash Risk","WARNING: Using a larger stepover value than tool's maximum with lines operation may result in a tool crash. Do you want to continue?")
			sys.stdout.write("%s"%(dr))
			if dr == True or dr == "yes" :
				app.setStatus(_("Risk Accepted")) #Using positive logic, if python returns ANYTHING other than True/yes this will not make g-code.  Incase Python uses No instead of False
			else:
				return
		if StockLeng <= 0 :
			app.setStatus(_("Spiral abort: Stock Length to cut must be positive"))
			return
			

		#Add Region disabled to show worked area
		block = Block(self.name + " Outline")
		block.enable = False
		block.append(CNC.grapid(CNC.vars["wx"],CNC.vars["wy"],ZApproach))  ## Cannot trust Safe-Z with 4th axis!!
		if AlignAxis == "X":
			outlineWidth = StockLeng
		else:
			outlineWidth = 0
		if AlignAxis == "Y":
			outlineHeight = StockLeng
		else:
			outlineHeight = 0
		xR,yR = self.RectPath(XStart,YStart,outlineWidth,outlineHeight)
		for x,y in zip(xR,yR):
			block.append(CNC.gline(x,y))
		blocks.append(block)

		
		if StockLeng < toolDiam :
			app.setStatus(_("Spiral abort: Stock Length is too small for this End Mill."))
			return

		#Prepare points for pocketing
		xP=[]
		yP=[]
		rP=[]
		zP=[]
		gP=[]
        

        #---------------------------------------------------------------------
        #Line approach
		if SpiralType == "Lines":
			#Calc number of indexes
			IndexNum = math.ceil(360/Stepover) # Using the step over as Degrees 
						

			#Calc number of pass
			VerticalCount = math.ceil(abs(ReduceDepth) / PassDepth)
			#Calc even depths of cut
			EvenCutDepths = ReduceDepth / VerticalCount
			
			currentR = 0
			currentZ = ZStart - EvenCutDepths
			direction = 1
			if AlignAxis == "X" :
				currentX = XStart + toolRadius
				currentY = YStart
			elif AlignAxis == "Y":
				currentX = XStart
				currentY = YStart + toolRadius
			else:
				app.setStatus(_("Spiral abort: Rotary Axis Not Assigned."))
				return			
			
			while (currentZ >= (ZStart + ReduceDepth)):
				#sys.stdout.write("~~~~~%s,%s,%s,%s,%s!"%(currentZ,ZStart,ReduceDepth,EvenCutDepths,VerticalCount))
				while (currentR < 360):
					#sys.stdout.write("~~~~~%s,%s,%s,%s,%s!"%(currentR,Stepover,currentX,currentY,VerticalCount))

					#Plunge in
					gP.append(1)
					rP.append(currentR)
					zP.append(currentZ)			
					xP.append(currentX)
					yP.append(currentY)
					if direction == 1:
						if AlignAxis == "X" :
							currentX = StockLeng - toolRadius
							currentY = YStart
						elif AlignAxis == "Y":
							currentX = XStart
							currentY = StockLeng - toolRadius
						else:
							app.setStatus(_("Spiral abort: Rotary Axis Not Assigned."))
							return
						if CutBoth == "True" :
							direction = -1
					else :
						if AlignAxis == "X" :
							currentX = XStart + toolRadius
							currentY = YStart
						elif AlignAxis == "Y":
							currentX = XStart
							currentY = YStart + toolRadius
						else:
							app.setStatus(_("Spiral abort: Rotary Axis Not Assigned."))
							return
						direction = 1
					gP.append(1)
					zP.append(currentZ)			
					xP.append(currentX)
					yP.append(currentY)
					rP.append(currentR)
					# Lift before rotating if required, useful to make non-round shape

					if CutBoth == "False" : # Return to start
					
						#Lift Before return
						gP.append(0)
						rP.append(currentR)
						zP.append(ZApproach)
						xP.append(currentX)
						yP.append(currentY)

						#Return to start
						if AlignAxis == "X" :
							currentX = XStart + toolRadius
							currentY = YStart
						elif AlignAxis == "Y":
							currentX = XStart
							currentY = YStart + toolRadius
						else:
							app.setStatus(_("Spiral abort: Rotary Axis Not Assigned."))
							return
						gP.append(0)
						xP.append(currentX)
						yP.append(currentY)
						rP.append(currentR)
						zP.append(ZApproach)
						#Rotate
						currentR += Stepover
						gP.append(0)
						xP.append(currentX)
						yP.append(currentY)
						rP.append(currentR)
						zP.append(ZApproach)
					elif LiftPass == "True" and CutBoth == "True" :
						gP.append(0)
						rP.append(currentR)
						zP.append(ZApproach)
						xP.append(currentX)
						yP.append(currentY)
						currentR += Stepover
						gP.append(0)
						xP.append(currentX)
						yP.append(currentY)
						rP.append(currentR)
						zP.append(ZApproach)
					elif LiftPass == "False" and CutBoth == "True" :
						currentR += Stepover
				gP.append(0)
				xP.append(currentX)
				yP.append(currentY)
				rP.append(currentR)
				zP.append(ZApproach)
				currentR=0
				gP.append(0)
				xP.append(currentX)
				yP.append(currentY)
				rP.append(currentR)
				zP.append(ZApproach)		

					
					
					
				#Step Down
				currentZ += EvenCutDepths			

		#---------------------------------------------------------------------
        #Spiral approach
		if SpiralType == "Spiral":
			#Calc number of pass
			StepsPerRot = math.ceil(StockLeng/Stepover)
			TotalRot = 360 * StepsPerRot
			
			#Calc steps in depth
			VerticalCount = math.ceil(abs(ReduceDepth) / PassDepth)
			#Calc even depths of cut
			EvenCutDepths = ReduceDepth / VerticalCount			
			
			direction = 1
			currentZ = ZStart - EvenCutDepths
			if AlignAxis == "X" :
				currentX = XStart + toolRadius
				currentY = YStart
			elif AlignAxis == "Y":
				currentX = XStart
				currentY = YStart + toolRadius
			else:
				app.setStatus(_("Spiral abort: Rotary Axis Not Assigned."))
				return
			currentR = 0
			while (currentZ >= (ZStart + ReduceDepth)):
				
				# Plunge to depth
				currentR += 90 # Ramp the Plunge
				gP.append(1)
				rP.append(currentR)
				zP.append(currentZ)			
				xP.append(currentX)
				yP.append(currentY)
				
				# One Full Rotation for a clean shoulder
				currentR += 360
				gP.append(1)
				rP.append(currentR)
				zP.append(currentZ)			
				xP.append(currentX)
				yP.append(currentY)
				
				
				if AlignAxis == "X" :
					if direction == 1:
						currentX = StockLeng - toolRadius
					else:
						currentX = XStart + toolRadius
					currentY = YStart
				elif AlignAxis == "Y":
					currentX = XStart
					if direction == 1:
						currentY = StockLeng - toolRadius
					else:
						currentY = YStart + toolRadius
				else:
					app.setStatus(_("Spiral abort: Rotary Axis Not Assigned."))
					return
					
				currentR += TotalRot
				gP.append(1)
				rP.append(currentR)
				zP.append(currentZ)			
				xP.append(currentX)
				yP.append(currentY)
				
				# One Full Rotation for a clean shoulder
				currentR += 360
				gP.append(1)
				rP.append(currentR)
				zP.append(currentZ)			
				xP.append(currentX)
				yP.append(currentY)
				
				if CutBoth == "True" : 
					direction *=  - 1
				else:
					#Retract
					gP.append(0)
					rP.append(currentR)
					zP.append(ZApproach)			
					xP.append(currentX)
					yP.append(currentY)
					# Return and Rewind
					gP.append(0)
					rP.append(currentR)
					zP.append(ZApproach)
					if AlignAxis == "X" :
						currentX = XStart + toolRadius
						currentY = YStart
					elif AlignAxis == "Y":
						currentX = XStart
						currentY = YStart + toolRadius
					else:
						app.setStatus(_("Spiral abort: Rotary Axis Not Assigned."))
						return
					xP.append(currentX)
					yP.append(currentY)
				
				
				currentZ += EvenCutDepths
				

#Start G-Code Processes
		#Blocks for pocketing
		block = Block(self.name)
		block.append("(Reduce Rotary by Y=%g)"%(ReduceDepth))
		block.append("(Approach: %s )" % (SpiralType))

		#Move safe to first point
		block.append(CNC.grapid(CNC.vars["mx"],CNC.vars["my"],ZApproach))  ## Cannot trust Safe-Z with 4th axis!!
		if AlignAxis == "X" :
			block.append(CNC.grapid(XStart + toolRadius,YStart))
		elif AlignAxis == "Y":
			block.append(CNC.grapid(XStart,YStart + toolRadius))
		else:
			app.setStatus(_("Spiral abort: Rotary Axis Not Assigned."))
			return
		
		block.append(CNC.zenter(ZApproach))
		block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])]))
		
		for g,x,y,z,r in zip(gP, xP,yP,zP, rP):
			if RotAxis == "A" :
				if g==0:
					block.append(CNC.grapidABC(x,y,z,r,CNC.vars["wb"],CNC.vars["wc"]))
					#sys.stdout.write("%s,%s,%s,%s,%s"%(g,x,y,z,r))
				else:
					block.append(CNC.glineABC(x,y,z,r,CNC.vars["wb"],CNC.vars["wc"]))
					#sys.stdout.write("%s,%s,%s,%s,%s"%(g,x,y,z,r))
			elif RotAxis == "B" :
				if g==0:
					block.append(CNC.grapidABC(x,y,z,CNC.vars["wa"],r,CNC.vars["wc"]))
				else:
					block.append(CNC.glineABC(x,y,z,CNC.vars["wa"],r,CNC.vars["wc"]))
			elif RotAxis == "C" :
				if g==0:
					block.append(CNC.grapidABC(x,y,z,CNC.vars["wa"],CNC.vars["wb"],r))
				else:
					block.append(CNC.glineABC(x,y,z,CNC.vars["wa"],CNC.vars["wb"],r))

			
		block.append(CNC.grapid(CNC.vars["wx"],CNC.vars["wy"],ZApproach))  ## Cannot trust Safe-Z with 4th axis!!
		if AlignAxis == "X" :
			block.append(CNC.grapid(XStart + toolRadius,YStart))
		elif AlignAxis == "Y":
			block.append(CNC.grapid(XStart,YStart + toolRadius))
		else:
			app.setStatus(_("Spiral abort: Rotary Axis Not Assigned."))
			return
		block.append(CNC.zexit(ZApproach))
		blocks.append(block)
		tkMessageBox.showinfo("Crash Risk","WARNING: Check CAM file Header for Z move. If it exists, remove it to prevent tool crash.")

		return blocks
Esempio n. 38
0
    def execute(self, app):
        name = self["name"]
        if not name or name == "default": name = "Default Name"
        sel_Blocks = self["Sel_Blocks"]
        #Get inputs
        x = self["X"]
        y = self["Y"]
        z = self["Z"]
        if z == "":
            z = CNC.vars["surface"]

        cutDiam = self["CutDiam"]
        cutRadius = cutDiam / 2.0
        if self["endmill"]:
            self.master["endmill"].makeCurrent(self["endmill"])
        toolDiam = CNC.vars["diameter"]
        #Radio = self["RadioHelix"]
        pitch = self["Pitch"]
        Depth = self["Depth"]
        Mult_F_Z = self["Mult_Feed_Z"]
        helicalCut = self["HelicalCut"]
        clearanceEntry = self["ClearanceEntry"]
        clearanceExit = self["ClearanceExit"]
        clearance = clearanceEntry
        entry = self["Entry"]
        returnToSafeZ = self["ReturnToSafeZ"]

        toolDiam = CNC.vars['diameter']
        toolRadius = toolDiam / 2.0
        Radio = cutRadius - toolRadius
        if (Radio < 0): Radio = 0

        toolDiam = CNC.vars['diameter']
        toolRadius = toolDiam / 2.0
        Radio = cutRadius - toolRadius

        if clearanceEntry == "":
            clearanceEntry = 0
        if clearanceExit == "":
            clearanceExit = 0

        if helicalCut == "Helical Cut":
            turn = 2
            p = "HelicalCut "
        elif helicalCut == "Internal Right Thread":
            turn = 2
            p = "IntRightThread "
        elif helicalCut == "Internal Left Thread":
            turn = 3
            p = "IntLeftThread "
        elif helicalCut == "External Right Thread":
            Radio = cutRadius + toolRadius
            turn = 2
            p = "ExtRightThread "
        elif helicalCut == "External Left Thread":
            Radio = cutRadius + toolRadius
            turn = 3
            p = "ExtLeftThread "

# 		------------------------------------------------------------------------------------------------------------------
#Check inputs
        if sel_Blocks == 0:
            if x == "" or y == "":
                app.setStatus(
                    _("If block selected false, please make a value of x"))
                return

        elif helicalCut == "":
            app.setStatus(_("Helical Abort: Please select helical type"))
            return

        elif cutDiam < toolDiam or cutDiam == "":
            app.setStatus(
                _("Helical Abort: Helix diameter must be greater than the end mill"
                  ))
            return

        elif cutDiam <= 0:
            app.setStatus(_("Helical Abort: Helix diameter must be positive"))
            return

        elif pitch <= 0 or pitch == "":
            app.setStatus(_("Helical Abort: Drop must be greater than 0"))
            return

        elif Mult_F_Z <= 0 or Mult_F_Z == "":
            app.setStatus(
                _("Helical Abort: Z Feed Multiplier must be greater than 0"))
            return

        elif entry == "":
            app.setStatus(
                _("Helical Abort: Please selecte Entry and Exit type"))
            return

        elif clearanceEntry < 0 or clearanceEntry == "":
            app.setStatus(
                _("Helical Abort: Entry Edge Clearence may be positive"))
            return

        elif clearanceExit < 0 or clearanceExit == "":
            app.setStatus(
                _("Helical Abort: Exit Edge Clearence may be positive"))
            return
# 		------------------------------------------------------------------------------------------------------------------
#Initialize blocks that will contain our gCode
        blocks = []
        #block = Block(name)
        block = Block(p + str(cutDiam) + " Pitch " + str(pitch) + " Bit " +
                      str(toolDiam) + " depth " + str(Depth))

        cutFeed = CNC.vars[
            "cutfeedz"]  #<<< Get cut feed Z for the current material
        cutFeedMax = CNC.vars[
            "cutfeed"]  #<<< Get cut feed XY for the current material
        # 		------------------------------------------------------------------------------------------------------------------
        # Get selected blocks from editor
        selBlocks = app.editor.getSelectedBlocks()
        if not selBlocks:
            app.editor.selectAll()
            selBlocks = app.editor.getSelectedBlocks()

        if not selBlocks:
            if sel_Blocks == 1:
                app.setStatus(_("Helical abort: Please select some path"))
                return
# 		------------------------------------------------------------------------------------------------------------------
# Get selected blocks from editor
        if sel_Blocks == 1:
            selBlocks = app.editor.getSelectedBlocks()
            if not selBlocks:
                app.editor.selectAll()
                selBlocks = app.editor.getSelectedBlocks()

            #Get all segments from gcode
            allSegments = self.extractAllSegments(app, selBlocks)

            #Create holes locations
            allHoles = []
            for bidSegment in allSegments:
                if len(bidSegment) == 0:
                    continue

                bidHoles = []
                for idx, anchor in enumerate(bidSegment):
                    if idx == 2:
                        newHolePoint = (anchor[0][0], anchor[0][1],
                                        anchor[0][2])
                        bidHoles.append(newHolePoint)

                #Add bidHoles to allHoles
                allHoles.append(bidHoles)

# 		------------------------------------------------------------------------------------------------------------------
            holesCount = 0
            for bid in allHoles:
                for xH, yH, zH in bid:
                    x = xH
                    y = yH

# 		------------------------------------------------------------------------------------------------------------------
#		 Init: Adjust feed and rapid move to Z safe

        if Mult_F_Z is "":
            Mult_F_Z = 1

        if Mult_F_Z == 0:
            Mult_F_Z = 1

        if Mult_F_Z * cutFeed > cutFeedMax:
            cutFeed = cutFeedMax
        else:
            cutFeed = cutFeed * Mult_F_Z

        block.append(CNC.zsafe(
        ))  #<<< Move rapid Z axis to the safe height in Stock Material

        #		 Move rapid to X and Y coordinate
        if helicalCut == "Helical Cut" or helicalCut == "Internal Right Thread" or helicalCut == "Internal Left Thread":
            if entry == "Center":
                block.append(CNC.grapid(x, y))
            else:
                block.append(CNC.grapid(x - Radio + clearance, y))

        if helicalCut == "External Right Thread" or helicalCut == "External Left Thread":
            if entry == "Center":
                clearance = 0.0
            block.append(CNC.grapid(x - Radio - clearance, y))

        #cutFeed = int(cutFeed)
        block.append(CNC.fmt("f", cutFeed))  #<<< Set cut feed
        #	block.append(CNC.gline(x,y)
        #    while (z < 1):
        block.append(CNC.zenter(z))
        block.append(CNC.gline(x - Radio, y))
        #	cutFeed = int((CNC.vars["cutfeed"]	+ CNC.vars["cutfeedz"])/2)	#<<< Get cut feed for the current material

        #cutFeed = int(cutFeed)
        block.append(CNC.fmt("F", cutFeed))  #<<< Set cut feed

        #-----------------------------------------------------------------------------------------------------
        #	Uncomment for first flat pass
        if helicalCut == "Helical Cut":
            block.append(
                CNC.gcode(turn, [("X", x - Radio), ("Y", y), ("Z", z),
                                 ("I", Radio), ("J", 0)]))
#-----------------------------------------------------------------------------------------------------
        if (z < Depth):
            pitch = -pitch

            while ((z - pitch) < Depth):
                z = z - pitch
                block.append(
                    CNC.gcode(turn, [("X", x - Radio), ("Y", y), ("Z", z),
                                     ("I", Radio), ("J", 0)]))

        else:
            while ((z - pitch) >= Depth):
                z = z - pitch
                block.append(
                    CNC.gcode(turn, [("X", x - Radio), ("Y", y), ("Z", z),
                                     ("I", Radio), ("J", 0)]))

        #Target Level
        if entry == "Center":
            clearanceExit = 0.0
        clearance = clearanceExit
        alpha = round(Depth / pitch, 4) - round(Depth / pitch, 0)
        alpha = alpha * 2 * pi
        Radiox = Radio * cos(alpha)
        Radioy = Radio * sin(alpha)
        xsi = Radiox - clearance * cos(alpha)
        ysi = Radioy - clearance * sin(alpha)
        xse = Radiox + clearance * cos(alpha)
        yse = Radioy + clearance * sin(alpha)
        z = Depth

        if helicalCut == "Helical Cut":
            block.append(
                CNC.gcode(turn, [("X", x - Radio), ("Y", y), ("Z", z),
                                 ("I", Radio), ("J", 0)]))
            #Last flat pass
            block.append(
                CNC.gcode(turn, [("X", x - Radio), ("Y", y), ("Z", z),
                                 ("I", Radio), ("J", 0)]))
        elif helicalCut == "Internal Right Thread" or helicalCut == "External Right Thread":
            block.append(
                CNC.gcode(turn, [("X", x - Radiox), ("Y", y - Radioy),
                                 ("Z", z), ("I", Radio), ("J", 0)]))

        elif helicalCut == "Internal Left Thread" or helicalCut == "External Left Thread":
            block.append(
                CNC.gcode(turn, [("X", x - Radiox), ("Y", y + Radioy),
                                 ("Z", z), ("I", Radio), ("J", 0)]))

        # Exit clearance
        if helicalCut == "Internal Right Thread":
            block.append(CNC.gline(x - xsi, y - ysi))
        elif helicalCut == "Internal Left Thread":
            block.append(CNC.gline(x - xsi, y + ysi))
        if helicalCut == "External Right Thread":
            block.append(CNC.gline(x - xse, y - yse))
        elif helicalCut == "External Left Thread":
            block.append(CNC.gline(x - xse, y + yse))

        # Return to Z Safe
        if returnToSafeZ == 1:
            if helicalCut == "Helical Cut" or helicalCut == "Internal Right Thread" or helicalCut == "Internal Left Thread":
                if entry == "Center":
                    block.append(CNC.gline(x, y))
            block.append(CNC.zsafe())

        blocks.append(block)
        active = app.activeBlock()
        app.gcode.insBlocks(
            active, blocks, "Helical_Descent inserted"
        )  #<<< insert blocks over active block in the editor
        app.refresh()  #<<< refresh editor
        app.setStatus(
            _("Generated: Helical_Descent Result"))  #<<< feed back result
Esempio n. 39
0
def line(self, app, end_depth, mem_0, mem_1):
    """Create GCode for a Line"""
    x_start = min(OCV.WK_mems[mem_0][0], OCV.WK_mems[mem_1][0])
    y_start = min(OCV.WK_mems[mem_0][1], OCV.WK_mems[mem_1][1])

    x_end = max(OCV.WK_mems[mem_0][0], OCV.WK_mems[mem_1][0])
    y_end = max(OCV.WK_mems[mem_0][1], OCV.WK_mems[mem_1][1])

    z_start = OCV.WK_mems[mem_1][2]

    tool_dia = OCV.CD['diameter']
    # tool_rad = tool_dia / 2.
    xy_stepover = tool_dia * OCV.CD['stepover'] / 100.0

    z_stepover = OCV.CD['stepz']

    # avoid infinite while loop
    if z_stepover == 0:
        z_stepover = 0.001

    msg = ("Line Cut Operation: \n",
           "Start: \n\n{0}\n\n".format(OCV.showC(x_start, y_start, z_start)),
           "End: \n\n{0}\n\n".format(OCV.showC(x_end, y_end, end_depth)),
           "Tool diameter: {0:.{1}f} \n\n".format(tool_dia, OCV.digits),
           "StepDown: {0:.{1}f} \n\n".format(z_stepover, OCV.digits),
           "StepOver: {0:.{1}f} \n\n".format(xy_stepover, OCV.digits))

    retval = tkMessageBox.askokcancel("Line Cut", "".join(msg))

    if OCV.DEBUG is True:
        print("RetVal", retval)

    if retval is False:
        return

    # Reset the Gcode in the Editor
    # Loading an empty file

    # Set the Initialization file
    blocks = []
    block = Block("Init")
    # Get the current WCS as the mem are related to it
    block.append(OCV.CD['WCS'])
    blocks.append(block)

    block = Block("Line")
    block.append("(Line Cut)")
    block.append("(From: {0})".format(OCV.gcodeCC(x_start, y_start, z_start)))
    block.append("(To: {0})".format(OCV.gcodeCC(x_end, y_end, end_depth)))
    block.append("(StepDown: {0:.{1}f} )".format(z_stepover, OCV.digits))
    block.append("(StepOver: {0:.{1}f} )".format(xy_stepover, OCV.digits))
    block.append("(Tool diameter = {0:.{1}f})".format(tool_dia, OCV.digits))

    # Safe move to first point
    block.append(CNC.zsafe())
    block.append(CNC.grapid(x_start, y_start))

    # Init Depth corrected by z_stepover
    # for the correctness of the loop
    # the first instruction of the while loop is -= z_stepover
    # the check is done at the final depth

    curr_depth = z_start + z_stepover

    # Create GCode from points
    while True:
        curr_depth -= z_stepover

        if curr_depth < end_depth:
            curr_depth = end_depth

        block.append(CNC.zenter(curr_depth))
        block.append(CNC.gcode_string(1, [("F", OCV.CD["cutfeed"])]))

        block.append(CNC.gline(x_end, y_end))

        # Move to start in a safe way
        block.append(CNC.zsafe())
        block.append(CNC.grapid(x_start, y_start))

        # Check exit condition
        if curr_depth <= end_depth:
            break

    # return to a safe Z
    block.append(CNC.zsafe())
    blocks.append(block)

    if blocks is not None:
        active = OCV.APP.activeBlock()

        if active == 0:
            active = 1

        OCV.APP.gcode.insBlocks(active, blocks, "Line Cut")
        OCV.APP.refresh()
        OCV.APP.setStatus(_("Line Cut: Generated line cut code"))
Esempio n. 40
0
	def execute(self, app):
		if Image is None:
			app.setStatus(_("Halftone abort: This plugin requires PIL/Pillow to read image data"))
			return

		n = self["name"]
		if not n or n=="default": n="Halftone"

		#Calc desired size
		channel = self["Channel"]
		invert = self["Invert"]
		drawSize = self["DrawSize"]
		cellSize = self["CellSize"]
		dMax = self["DiameterMax"]
		dMin = self["DiameterMin"]
		angle = self["Angle"]
		drawBorder = self["DrawBorder"]
		depth = self["Depth"]
		conical = self["Conical"]

		#Check parameters
		if drawSize < 1:
			app.setStatus(_("Halftone abort: Size too small to draw anything!"))
			return

		if dMin > dMax:
			app.setStatus(_("Halftone abort: Minimum diameter must be minor then Maximum"))
			return

		if dMax < 1:
			app.setStatus(_("Halftone abort: Maximum diameter too small"))
			return

		if cellSize < 1:
			app.setStatus(_("Halftone abort: Cell size too small"))
			return

		tool = app.tools["EndMill"]
		tool_shape = tool["shape"]
		if conical:
			if tool_shape== "V-cutting":
				try:
					v_angle = float(tool["angle"])
				except:
					app.setStatus(_("Halftone abort: Angle in V-Cutting end mill is missing"))
					return
			else:
				app.setStatus(_("Halftone abort: Conical path need V-Cutting end mill"))
				return

		#Open picture file
		fileName = self["File"]
		try:
			img = Image.open(fileName)
		except:
			app.setStatus(_("Halftone abort: Can't read image file"))
			return

		#Create a scaled image to work faster with big image and better with small ones
		squareNorm = True
		if channel == 'Blue(sqrt)':
			img = img.convert('RGB')
			img = img.split()[0]
		elif channel == 'Green(sqrt)':
			img = img.convert('RGB')
			img = img.split()[1]
		elif channel == 'Red(sqrt)':
			img = img.convert('RGB')
			img = img.split()[2]
		else:
			img = img.convert ('L') #to calculate luminance
			squareNorm = False

		 #flip image to ouput correct coordinates
		img = img.transpose(Image.FLIP_TOP_BOTTOM)

		#Calc divisions for halftone
		divisions = drawSize / cellSize
		#Get image size
		self.imgWidth, self.imgHeight =  img.size
		if (self.imgWidth > self.imgHeight):
			scale = drawSize / float(self.imgWidth)
			sample = int(self.imgWidth / divisions)
		else:
			scale = drawSize / float(self.imgHeight)
			sample = int(self.imgHeight / divisions)
		self.ratio = scale

		#Halftone
		circles = self.halftone(img, sample, scale, angle, squareNorm, invert)

		#Init blocks
		blocks = []

		#Border block
		if drawBorder:
			block = Block("%s-border"%(self.name))
			block.append(CNC.zsafe())
			block.append(CNC.grapid(0,0))
			block.append(CNC.zenter(depth))
			block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])]))
			block.append(CNC.gline(self.imgWidth * self.ratio, 0))
			block.append(CNC.gline(self.imgWidth * self.ratio, self.imgHeight*self.ratio))
			block.append(CNC.gline(0, self.imgHeight*self.ratio))
			block.append(CNC.gline(0,0))
			blocks.append(block)

		#Draw block
		block = Block(self.name)

		#Change color
		if channel == 'Blue(sqrt)':
			block.color = "#0000ff"
		elif channel == 'Green(sqrt)':
			block.color = "#00ff00"
		elif channel == 'Red(sqrt)':
			block.color = "#ff0000"

		block.append("(Halftone size W=%d x H=%d x D=%d ,Total points:%i)" %
			 (self.imgWidth * self.ratio, self.imgHeight * self.ratio, depth, len(circles)))
		block.append("(Channel = %s)" % channel)

		for c in circles:
			x,y,r = c
			r = min(dMax/2.0,r)
			if (r >= dMin/2.):
				block.append(CNC.zsafe())
				block.append(CNC.grapid(x+r,y))
				block.append(CNC.zenter(depth))
				block.append(CNC.garc(CW,x+r,y,i=-r,))
		block.append(CNC.zsafe())
		if conical: block.enable = False
		blocks.append(block)

		if conical:
			blockCon = Block("%s-Conical"%(self.name))
			for c in circles:
				x,y,r = c
				blockCon.append(CNC.zsafe())
				blockCon.append(CNC.grapid(x,y))
				dv = r / math.tan(math.radians(v_angle/2.))
				blockCon.append(CNC.zenter(-dv))
			blockCon.append(CNC.zsafe())
			blocks.append(blockCon)

		#Gcode Zsafe
		active = app.activeBlock()
		app.gcode.insBlocks(active, blocks, "Halftone")
		app.refresh()
		app.setStatus(_("Generated Halftone size W=%d x H=%d x D=%d ,Total points:%i" %
			 (self.imgWidth * self.ratio, self.imgHeight * self.ratio, depth, len(circles))))
Esempio n. 41
0
    def execute(self, app):

        n = self["name"]
        if not n or n == "default": n = "Pyrograph"

        #Import parameters
        toolSize = self.fromMm("ToolSize")

        if toolSize <= 0:
            app.setStatus(_("Pyrograph abort: Tool Size must be > 0"))
            return

        filename = self["File"]

        #Open gcode file
        if not (filename == ""):
            app.load(filename)

        inOut = self["In-Out"]
        xadd = self["xAdd"]
        yadd = self["yAdd"]
        if xadd == "": xadd = 1
        if yadd == "": yadd = 1

        #Create the external box
        if inOut == "Out":
            box = Block("Box")
            external_box = []
            box.append(
                CNC.grapid(CNC.vars["xmin"] - xadd, CNC.vars["ymin"] - yadd))
            box.append(
                CNC.gline(CNC.vars["xmin"] - xadd, CNC.vars["ymax"] + yadd))
            box.append(
                CNC.gline(CNC.vars["xmax"] + xadd, CNC.vars["ymax"] + yadd))
            box.append(
                CNC.gline(CNC.vars["xmax"] + xadd, CNC.vars["ymin"] - yadd))
            box.append(
                CNC.gline(CNC.vars["xmin"] - xadd, CNC.vars["ymin"] - yadd))

            #Insert the external block
            external_box.append(box)
            app.gcode.insBlocks(1, external_box, "External_Box")
            app.refresh()

        #Value for creating an offset from the margins of the gcode
        margin = self.fromMm(
            "Margin"
        )  #GIVING RANDOM DECIMALS SHOULD AVOID COINCIDENT SEGMENTS BETWEEN ISLAND AND BASE PATHS THAT CONFUSE THE ALGORITHM. WORKS IN MOST CASES.

        #Add and subtract the margin
        max_x = CNC.vars["xmax"] + margin
        min_x = CNC.vars["xmin"] - margin
        max_y = CNC.vars["ymax"] + margin
        min_y = CNC.vars["ymin"] - margin

        #Difference between offtset margins
        dx = max_x - min_x
        dy = max_y - min_y

        #Number of vertical divisions according to the toolsize
        divisions = dy / toolSize

        #Distance between horizontal lines
        step_y = toolSize
        n_steps_y = int(divisions) + 1

        #Create the snake pattern according to the number of divisions
        pattern = Block(self.name)
        pattern_base = []

        for n in range(n_steps_y):
            if n == 0:
                pattern.append(CNC.grapid(min_x, min_y))  #go to bottom left
            else:
                y0 = min_y + step_y * (n - 1)
                y1 = min_y + step_y * (n)
                if not (n % 2 == 0):
                    pattern.append(CNC.glinev(
                        1, [max_x, y0]))  #write odd lines from left to right
                    pattern.append(CNC.grapid(max_x, y1))
                else:
                    pattern.append(CNC.glinev(
                        1, [min_x, y0]))  #write even lines from right to left
                    pattern.append(CNC.grapid(min_x, y1))

        #Insert the pattern block
        pattern_base.append(pattern)
        app.gcode.insBlocks(1, pattern_base, "pattern")
        app.refresh()

        #Mark pattern as island
        for bid in pattern_base:
            app.gcode.island([1])

        #Select all blocks
        app.editor.selectAll()

        paths_base = []
        paths_isl = []

        points = []

        #Compare blocks to separate island from other blocks
        for bid in app.editor.getSelectedBlocks():
            if app.gcode[bid].operationTest('island'):
                paths_isl.extend(app.gcode.toPath(bid))
            else:
                paths_base.extend(app.gcode.toPath(bid))

        #Make intersection between blocks
        while len(paths_base) > 0:
            base = paths_base.pop()
            for island in paths_isl:
                #points.extend(base.intersectPath(island))
                points.extend(island.intersectPath(base))

###SORTING POINTS###
        x = []
        y = []

        #Get (x,y) intersection points
        for i in range(len(points)):
            x.append(points[i][2][0])
            y.append(points[i][2][1])

        #Save (x,y) intersection points in a matrix
        matrix = [[0 for i in range(2)] for j in range(len(x))]

        for i in range(len(x)):
            matrix[i][0] = x[i]
            matrix[i][1] = y[i]

        # for i in range(len(x)):
        # 	print('puntos',points[i][0],points[i][1],matrix[i][0], matrix[i][1])

        #print(matrix)

        #Sort points in increasing y coordinate
        matrix.sort(key=itemgetter(1, 0), reverse=False)

        # for i in range(len(x)):
        # 	print('puntos',points[i][0],points[i][1],matrix[i][0], matrix[i][1])
        #print(matrix)

        index = 0
        pair = 0
        new_matrix = []
        for i in range(len(x)):
            if i == 0:
                index = index + 1
            elif i < len(x) - 1:
                if matrix[i][1] == matrix[i - 1][1]:
                    index = index + 1
                else:
                    if pair % 2 == 0:
                        logic = False
                    else:
                        logic = True
                    submatrix = matrix[i - index:i]
                    submatrix.sort(key=itemgetter(0, 1), reverse=logic)
                    new_matrix.extend(submatrix)
                    index = 1
                    pair = pair + 1
            else:
                #print('entered')
                if pair % 2 == 0:
                    logic = False
                else:
                    logic = True
                if matrix[i][1] == matrix[i - 1][1]:
                    submatrix = matrix[i - index:]
                    submatrix.sort(key=itemgetter(0, 1), reverse=logic)
                    new_matrix.extend(submatrix)
                else:
                    index = 1
                    submatrix = matrix[-1]
                    new_matrix.extend(submatrix)

        # for i in range(len(x)):
        # 	print('puntos',new_matrix[i][0], new_matrix[i][1])

        # for i in range(len(x)):
        # 	print('puntos',new_matrix[i][0], new_matrix[i][1])
        #print(x, y)

###SORTING POINTS END###

#Generate the gcode from points obtained
        blocks = []
        block = Block(self.name)

        for i in range(len(x)):
            if i == 0:
                block.append(CNC.grapid(new_matrix[0][0], new_matrix[0][1]))
                inside = 0
            else:
                if inside == 0:
                    block.append(CNC.gline(new_matrix[i][0], new_matrix[i][1]))
                    inside = 1
                else:
                    block.append(CNC.grapid(new_matrix[i][0],
                                            new_matrix[i][1]))
                    inside = 0

        # for i in range(len(x)):
        # 	print('puntos',x[i], y[i])

        blocks.append(block)
        app.gcode.delBlockUndo(1)
        app.gcode.insBlocks(1, blocks, "Line to Line Burning")

        app.editor.disable()

        for block in blocks:
            block.enable = 1

        #app.editor.enable()
        #app.editor.unselectAll()
        app.refresh()
        app.setStatus(_("Generated Line to Line Burning"))
Esempio n. 42
0
    def make(self,app, XStart=0.0, YStart=0.0, FlatWidth=10., FlatHeight=10., \
      FlatDepth=0, BorderPass=False, CutDirection="Climb", PocketType="Raster"):

        #GCode Blocks
        blocks = []

        #Check parameters
        if CutDirection == "":
            app.setStatus(_("Flatten abort: Cut Direction is undefined"))
            return

        if PocketType == "":
            app.setStatus(_("Flatten abort: Pocket Type is undefined"))
            return

        if FlatWidth <= 0 or FlatHeight <= 0:
            app.setStatus(
                _("Flatten abort: Flatten Area dimensions must be > 0"))
            return

        if FlatDepth > 0:
            app.setStatus(
                _("Flatten abort: Hey this is only for subtractive machine! Check depth!"
                  ))
            return

        #Add Region disabled to show worked area
        block = Block(self.name + " Outline")
        block.enable = False
        block.append(CNC.zsafe())
        xR, yR = self.RectPath(XStart, YStart, FlatWidth, FlatHeight)
        for x, y in zip(xR, yR):
            block.append(CNC.gline(x, y))
        blocks.append(block)

        # Load tool and material settings
        toolDiam = CNC.vars['diameter']
        toolRadius = toolDiam / 2.

        #Calc tool diameter with Maximum Step Over allowed
        StepOverInUnitMax = toolDiam * CNC.vars['stepover'] / 100.0

        #Offset for Border Cut
        BorderXStart = XStart + toolRadius
        BorderYStart = YStart + toolRadius
        BorderWidth = FlatWidth - toolDiam
        BorderHeight = FlatHeight - toolDiam
        BorderXEnd = XStart + FlatWidth - toolRadius
        BorderYEnd = YStart + FlatHeight - toolRadius

        PocketXStart = BorderXStart
        PocketYStart = BorderYStart
        PocketXEnd = BorderXEnd
        PocketYEnd = BorderYEnd

        #Calc space to work with/without border cut
        WToWork = FlatWidth - toolDiam
        HToWork = FlatHeight - toolDiam

        if (WToWork < toolRadius or HToWork < toolRadius):
            app.setStatus(
                _("Flatten abort: Flatten area is too small for this End Mill."
                  ))
            return

        #Prepare points for pocketing
        xP = []
        yP = []
        #and border
        xB = []
        yB = []

        #---------------------------------------------------------------------
        #Raster approach
        if PocketType == "Raster":
            #Correct sizes if border is used
            if (BorderPass):
                PocketXStart += StepOverInUnitMax
                PocketYStart += StepOverInUnitMax
                PocketXEnd -= StepOverInUnitMax
                PocketYEnd -= StepOverInUnitMax
                WToWork -= (StepOverInUnitMax)
                HToWork -= (StepOverInUnitMax)

            #Calc number of pass
            VerticalCount = (int)(HToWork / StepOverInUnitMax)
            #Calc step minor of Max step
            StepOverInUnit = HToWork / (VerticalCount + 1)
            flip = False
            ActualY = PocketYStart
            #Zig zag
            if StepOverInUnit == 0:
                StepOverInUnit = 0.001  #avoid infinite while loop
            while (True):
                #Zig
                xP.append(self.ZigZag(flip, PocketXStart, PocketXEnd))
                yP.append(ActualY)
                flip = not flip
                #Zag
                xP.append(self.ZigZag(flip, PocketXStart, PocketXEnd))
                yP.append(ActualY)
                if (ActualY >=
                        PocketYEnd - StepOverInUnitMax + StepOverInUnit):
                    break
                #Up
                ActualY += StepOverInUnit
                xP.append(self.ZigZag(flip, PocketXStart, PocketXEnd))
                yP.append(ActualY)

            #Points for border cut depends on Zig/Zag end
            if (BorderPass):
                if flip:
                    xB, yB = self.RectPath(BorderXStart, BorderYEnd,
                                           BorderWidth, -BorderHeight)
                else:
                    xB, yB = self.RectPath(BorderXEnd, BorderYEnd,
                                           -BorderWidth, -BorderHeight)

                #Reverse in case of Climb
                if CutDirection == "Climb":
                    xB = xB[::-1]
                    yB = yB[::-1]

        #---------------------------------------------------------------------
        #Offset approach
        if PocketType == "Offset":
            #Calc number of pass
            VerticalCount = (int)(HToWork / StepOverInUnitMax)
            HorrizontalCount = (int)(WToWork / StepOverInUnitMax)
            #Make them odd
            if VerticalCount % 2 == 0: VerticalCount += 1
            if HorrizontalCount % 2 == 0: HorrizontalCount += 1
            #Calc step minor of Max step
            StepOverInUnitH = HToWork / (VerticalCount)
            StepOverInUnitW = WToWork / (HorrizontalCount)

            #Start from border to center
            xS = PocketXStart
            yS = PocketYStart
            wS = WToWork
            hS = HToWork
            xC = 0
            yC = 0
            while (xC <= HorrizontalCount / 2 and yC <= VerticalCount / 2):
                #Pocket offset points
                xO, yO = self.RectPath(xS, yS, wS, hS)
                if CutDirection == "Conventional":
                    xO = xO[::-1]
                    yO = yO[::-1]

                xP = xP + xO
                yP = yP + yO
                xS += StepOverInUnitH
                yS += StepOverInUnitW
                hS -= 2.0 * StepOverInUnitH
                wS -= 2.0 * StepOverInUnitW
                xC += 1
                yC += 1

            #Reverse point to start from inside (less stress on the tool)
            xP = xP[::-1]
            yP = yP[::-1]

        #Blocks for pocketing
        block = Block(self.name)
        block.append("(Flatten from X=%g Y=%g)" % (XStart, YStart))
        block.append("(W=%g x H=%g x D=%g)" %
                     (FlatWidth, FlatHeight, FlatDepth))
        block.append("(Approach: %s %s)" % (PocketType, CutDirection))
        if BorderPass: block.append("(with border)")

        #Move safe to first point
        block.append(CNC.zsafe())
        block.append(CNC.grapid(xP[0], yP[0]))
        #Init Depth
        currDepth = 0.
        stepz = CNC.vars['stepz']
        if stepz == 0: stepz = 0.001  #avoid infinite while loop

        #Create GCode from points
        while True:
            currDepth -= stepz
            if currDepth < FlatDepth: currDepth = FlatDepth
            block.append(CNC.zenter(currDepth))
            block.append(CNC.gcode(1, [("f", CNC.vars["cutfeed"])]))

            #Pocketing
            lastxy = None
            for x, y in zip(xP, yP):
                #				block.append(CNC.gline(x,y))
                if lastxy != CNC.gline(x, y) or None:
                    block.append(CNC.gline(x, y))
                lastxy = CNC.gline(x, y)

            #Border cut if request
            for x, y in zip(xB, yB):
                block.append(CNC.gline(x, y))

            #Verify exit condition
            if currDepth <= FlatDepth: break

            #Move to the begin in a safe way
            block.append(CNC.zsafe())
            block.append(CNC.grapid(xP[0], yP[0]))

        #Zsafe
        block.append(CNC.zsafe())
        blocks.append(block)
        return blocks
Esempio n. 43
0
    def execute(self, app):
        if Image is None:
            app.setStatus(
                _("Halftone abort: This plugin requires PIL/Pillow to read image data"
                  ))
            return

        n = self["name"]
        if not n or n == "default": n = "Halftone"

        # Calc desired size
        channel = self["Channel"]
        invert = self["Invert"]
        drawSize = self["DrawSize"]
        cellSize = self["CellSize"]
        dMax = self["DiameterMax"]
        dMin = self["DiameterMin"]
        angle = self["Angle"]
        drawBorder = self["DrawBorder"]
        depth = self["Depth"]
        conical = self["Conical"]

        # Check parameters
        if drawSize < 1:
            app.setStatus(
                _("Halftone abort: Size too small to draw anything!"))
            return

        if dMin > dMax:
            app.setStatus(
                _("Halftone abort: Minimum diameter must be minor then Maximum"
                  ))
            return

        if dMax < 1:
            app.setStatus(_("Halftone abort: Maximum diameter too small"))
            return

        if cellSize < 1:
            app.setStatus(_("Halftone abort: Cell size too small"))
            return

        tool = app.tools["EndMill"]
        tool_shape = tool["shape"]
        if conical:
            if tool_shape == "V-cutting":
                try:
                    v_angle = float(tool["angle"])
                except:
                    app.setStatus(
                        _("Halftone abort: Angle in V-Cutting end mill is missing"
                          ))
                    return
            else:
                app.setStatus(
                    _("Halftone abort: Conical path need V-Cutting end mill"))
                return

        # Open picture file
        fileName = self["File"]
        try:
            img = Image.open(fileName)
        except:
            app.setStatus(_("Halftone abort: Can't read image file"))
            return

        # Create a scaled image to work faster with big image and better with small ones
        squareNorm = True
        if channel == 'Blue(sqrt)':
            img = img.convert('RGB')
            img = img.split()[0]
        elif channel == 'Green(sqrt)':
            img = img.convert('RGB')
            img = img.split()[1]
        elif channel == 'Red(sqrt)':
            img = img.convert('RGB')
            img = img.split()[2]
        else:
            img = img.convert('L')  # to calculate luminance
            squareNorm = False

        # flip image to ouput correct coordinates
        img = img.transpose(Image.FLIP_TOP_BOTTOM)

        # Calc divisions for halftone
        divisions = drawSize / cellSize
        # Get image size
        self.imgWidth, self.imgHeight = img.size
        if (self.imgWidth > self.imgHeight):
            scale = drawSize / float(self.imgWidth)
            sample = int(self.imgWidth / divisions)
        else:
            scale = drawSize / float(self.imgHeight)
            sample = int(self.imgHeight / divisions)
        self.ratio = scale

        # Halftone
        circles = self.halftone(img, sample, scale, angle, squareNorm, invert)

        # Init blocks
        blocks = []

        # Border block
        if drawBorder:
            block = Block("%s-border" % (self.name))
            block.append(CNC.zsafe())
            block.append(CNC.grapid(0, 0))
            block.append(CNC.zenter(depth))
            block.append(CNC.gcode(1, [("f", CNC.vars["cutfeed"])]))
            block.append(CNC.gline(self.imgWidth * self.ratio, 0))
            block.append(
                CNC.gline(self.imgWidth * self.ratio,
                          self.imgHeight * self.ratio))
            block.append(CNC.gline(0, self.imgHeight * self.ratio))
            block.append(CNC.gline(0, 0))
            blocks.append(block)

        # Draw block
        block = Block(self.name)

        # Change color
        if channel == 'Blue(sqrt)':
            block.color = "#0000ff"
        elif channel == 'Green(sqrt)':
            block.color = "#00ff00"
        elif channel == 'Red(sqrt)':
            block.color = "#ff0000"

        block.append("(Halftone size W=%d x H=%d x D=%d ,Total points:%i)" %
                     (self.imgWidth * self.ratio, self.imgHeight * self.ratio,
                      depth, len(circles)))
        block.append("(Channel = %s)" % channel)

        for c in circles:
            x, y, r = c
            r = min(dMax / 2.0, r)
            if (r >= dMin / 2.):
                block.append(CNC.zsafe())
                block.append(CNC.grapid(x + r, y))
                block.append(CNC.zenter(depth))
                block.append(CNC.garc(
                    CW,
                    x + r,
                    y,
                    i=-r,
                ))
        block.append(CNC.zsafe())
        if conical: block.enable = False
        blocks.append(block)

        if conical:
            blockCon = Block("%s-Conical" % (self.name))
            for c in circles:
                x, y, r = c
                blockCon.append(CNC.zsafe())
                blockCon.append(CNC.grapid(x, y))
                dv = r / math.tan(math.radians(v_angle / 2.))
                blockCon.append(CNC.zenter(-dv))
            blockCon.append(CNC.zsafe())
            blocks.append(blockCon)

        # Gcode Zsafe
        active = app.activeBlock()
        app.gcode.insBlocks(active, blocks, "Halftone")
        app.refresh()
        app.setStatus(
            _("Generated Halftone size W=%d x H=%d x D=%d ,Total points:%i" %
              (self.imgWidth * self.ratio, self.imgHeight * self.ratio, depth,
               len(circles))))
Esempio n. 44
0
    def execute(self, app):
        name = self['name']

        if not name or name == 'default':
            name = 'Function'

        # Initialize blocks that will contain our gCode
        blocks = []
        block = Block(name)

        #Variable definitions
        formula = self['form']
        res = self['res']  # X resolution
        ran = [self['ranX'], self['ranY']]  # Range of X,Y, from -10, to 10 range is 20
        cent = [self['centX'], self['centY']]  # Coordinates X,Y of the center from bottom left of the coordinate system
        dim = [self['dimX'], self['dimY']]  # Real dimensions in gcode units
        spacX = self['spacX']  # Spacing of X axis lines
        spacY = self['spacY']  # Spacing of Y axis lines
        lin = self['lin']  # Small value - length of a line in gcode units
        draw = self['draw']  # Draw the coordinate system

        block.append("(Generated with a script by kswiorek)\n")
        block.append("(Equation: " + formula +")\n")
        block.append("(Resolution: " + str(res) +")\n")
        block.append("(Range: " + str(ran) +")\n")
        block.append("(Center: " + str(cent) +")\n")
        block.append("(Dimensions: " + str(dim) +")\n")
        block.append("(SpacingXY: " + str(spacX) +", " + str(spacY) +")\n")

        def mapc(var, axis): #Map coordinate systems
            return (var * (dim[axis]/ran[axis]))

        #Define coordinate system mins and maxes
        minX = -cent[0]
        maxX = ran[0]-cent[0]

        minY = -cent[1]
        maxY = ran[1]-cent[1]

        #Define domain and codomain
        X = []
        Y = []

        e_old = "" #Store old exception to comapre

        #Calculate values for arguments with a resolution
        for i in range(0, int(ran[0]/res+1)): #Complaints about values beeing floats
            x = i*res + minX #Iterate x
            X.append(x)
            try:
                Y.append(eval(formula))

            except Exception as exc: #Append None, not to loose sync with X
                Y.append(None)
                e = str(exc)
                if e != e_old: #If there is a different exception - display it
                    print("Warning: " + str(e))
                    app.setStatus(_("Warning: " + str(e)))
                    e_old = e

        raised = True # Z axis is raised at start

        #Clip values out of bounds, replace with None, not to loose sync with X
        for i, item in enumerate(Y):
            y = Y[i]
            if not y is None and (y < minY or y > maxY):
                Y[i] = None

        #Y without "None", min() and max() can't compare them
        Ynn = [] #Y no Nones
        for i, item in enumerate(Y):
            if not Y[i] is None:
                Ynn.append(Y[i])

        block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])])) #Set feedrate

        if draw: #If the user selected to draw the coordinate system
            #X axis
            block.append(CNC.grapid(z=3))
            block.append(CNC.grapid(0, mapc(cent[1], 1))) #1st point of X axis line
            block.append(CNC.grapid(z=0))

            block.append(CNC.gline(dim[0] + lin*1.2, mapc(cent[1], 1))) #End of X axis line + a bit more for the arrow

            block.append(CNC.gline(dim[0] - lin/2, mapc(cent[1], 1) - lin / 2)) #bottom part of the arrow

            block.append(CNC.grapid(z=3))
            block.append(CNC.grapid(dim[0] + lin*1.2, mapc(cent[1], 1), 0)) #End of X axis line
            block.append(CNC.grapid(z=0))

            block.append(CNC.gline(dim[0] - lin/2, mapc(cent[1], 1) + lin / 2)) #top part of the arrow
            block.append(CNC.grapid(z=3))

            #Y axis, just inverted x with y
            block.append(CNC.grapid(z=3))
            block.append(CNC.grapid(mapc(cent[0], 0), 0)) #1st point of Y axis line
            block.append(CNC.grapid(z=0))

            block.append(CNC.gline(mapc(cent[0], 0), dim[1] + lin*1.2)) #End of Y axis line + a bit more for the arrow

            block.append(CNC.gline(mapc(cent[0], 0) - lin / 2, dim[1] - lin/2)) #left part of the arrow

            block.append(CNC.grapid(z=3))
            block.append(CNC.grapid(mapc(cent[0], 0), dim[1] + lin*1.2)) #End of Y axis line
            block.append(CNC.grapid(z=0))

            block.append(CNC.gline(mapc(cent[0], 0) + lin / 2, dim[1] - lin/2)) #right part of the arrow
            block.append(CNC.grapid(z=3))

            #X axis number lines
            i = 0
            while i < ran[0] - cent[0]: #While i is on the left of the arrow
                i +=spacX #Add line spacing

                #Draw lines right of the center
                block.append(CNC.grapid(mapc(i+cent[0],0), mapc(cent[1], 1) + lin/2))
                block.append(CNC.grapid(z=0))
                block.append(CNC.gline(mapc(i+cent[0],0), mapc(cent[1], 1) - lin/2))
                block.append(CNC.grapid(z=3))

            i = 0
            while i > -cent[0]: #While i is lower than center coordinate, inverted for easier math
                i -=spacX #Add line spacing

                #Draw lines left of the center
                block.append(CNC.grapid(mapc(i+cent[0],0), mapc(cent[1], 1) + lin/2))
                block.append(CNC.grapid(z=0))
                block.append(CNC.gline(mapc(i+cent[0],0), mapc(cent[1], 1) - lin/2))
                block.append(CNC.grapid(z=3))

            #Y axis number lines
            i = 0
            while i < ran[1] - cent[1]: #While i is between the center and the arrow
                i +=spacX #Add line spacing

                #Draw lines top of the center (everything just inverted)
                block.append(CNC.grapid(mapc(cent[0], 0) + lin/2, mapc(i+cent[1],1)))
                block.append(CNC.grapid(z=0))
                block.append(CNC.gline(mapc(cent[0], 0) - lin/2, mapc(i+cent[1],1)))
                block.append(CNC.grapid(z=3))

            i = 0
            while i > -1*cent[1]:
                i -=spacX #Add line spacing

                #Draw lines bottom of the center
                block.append(CNC.grapid(mapc(cent[0], 0) + lin/2, mapc(i+cent[1],1)))
                block.append(CNC.grapid(z=0))
                block.append(CNC.gline(mapc(cent[0], 0) - lin/2, mapc(i+cent[1],1)))
                block.append(CNC.grapid(z=3))

            raised = True #Z was raised

        #Draw graph
        for i, item in enumerate(Y):
            if not Y[i] is None:
                x = mapc(X[i]+cent[0], 0) #Take an argument
                y = mapc(Y[i]+cent[1], 1) #Take a value
            else:
                y = Y[i] #only for tne None checks next

            if y is None and not raised: #If a None "period" just started raise Z
                raised = True
                block.append(CNC.grapid(z=3))
            elif not y is None and raised: #If Z was raised and the None "period" ended move to new coordinates
                block.append(CNC.grapid(round(x, 2),round(y, 2)))
                block.append(CNC.grapid(z=0)) #Lower Z
                raised = False
            elif not y is None and not raised: #Nothing to do with Nones? Just draw
                block.append(CNC.gline(round(x, 2),round(y, 2)))

        block.append(CNC.grapid(z=3)) #Raise on the end

        blocks.append(block)
        active = app.activeBlock()
        app.gcode.insBlocks(active, blocks, 'Function inserted')  #insert blocks over active block in the editor
        app.refresh()  #refresh editor
        app.setStatus(_('Generated function graph'))  #feed back result
        print()