Esempio n. 1
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. 2
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. 3
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. 4
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. 5
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. 6
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. 7
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. 8
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. 9
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. 10
0
    def _rectangle(self, block, x0, y0, dx, dy, nx, ny, ex=0., ey=0.):
        block.append("(  Location: %g,%g )" % (x0, y0))
        block.append("(  Dimensions: %g,%g )" % (dx, dy))
        block.append("(  Teeth: %d,%d )" % (nx, ny))
        block.append("(  Tool diameter: %g )" % (self.tool))

        # Start with full length
        sx = dx / abs(nx)
        sy = dy / abs(ny)

        # Bottom
        pos = Vector(x0, y0, self.surface)
        pos -= self.r * Vector.Y  # r*V
        block.append(CNC.gcode(0, zip("XY", pos[:2])))

        z = self.surface
        #for z in frange(self.surface-self.stepz, self.surface-self.thick, -self.stepz):
        last = False
        while True:
            if self.cut:
                z -= self.stepz
                if z <= self.surface - self.thick:
                    z = self.surface - self.thick
                    last = True
            else:
                last = True

            pos[2] = z

            # Penetrate
            block.append(CNC.zenter(pos[2]))

            # Bottom
            pos = self.zigZagLine(block, pos, sx, self.thick, Vector.X,
                                  Vector.Y, nx, ex)
            block.append("")

            # Right
            pos = self.zigZagLine(block, pos, sy, self.thick, Vector.Y,
                                  -Vector.X, ny, ey)
            block.append("")

            # Top
            pos = self.zigZagLine(block, pos, sx, self.thick, -Vector.X,
                                  -Vector.Y, nx, ex)
            block.append("")

            # Right
            pos = self.zigZagLine(block, pos, sy, self.thick, -Vector.Y,
                                  Vector.X, ny, ey)
            block.append("")
            if last: break

        # Bring to safe height
        block.append(CNC.zsafe())
Esempio n. 11
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. 12
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. 13
0
	def _rectangle(self, block, x0, y0, dx, dy, nx, ny, ex=0., ey=0.):
		block.append("(  Location: %g,%g )"%(x0,y0))
		block.append("(  Dimensions: %g,%g )"%(dx,dy))
		block.append("(  Teeth: %d,%d )"%(nx,ny))
		block.append("(  Tool diameter: %g )"%(self.tool))

		# Start with full length
		sx = dx / abs(nx)
		sy = dy / abs(ny)

		# Bottom
		pos = Vector(x0, y0, self.surface)
		pos -= self.r*Vector.Y	# r*V
		block.append(CNC.gcode(0, zip("XY",pos[:2])))

		z = self.surface
		#for z in frange(self.surface-self.stepz, self.surface-self.thick, -self.stepz):
		last = False
		while True:
			if self.cut:
				z -= self.stepz
				if z <= self.surface - self.thick:
					z = self.surface - self.thick
					last = True
			else:
				last = True

			pos[2] = z

			# Penetrate
			block.append(CNC.zenter(pos[2]))

			# Bottom
			pos = self.zigZagLine(block, pos, sx, self.thick, Vector.X, Vector.Y, nx, ex)
			block.append("")

			# Right
			pos = self.zigZagLine(block, pos, sy, self.thick, Vector.Y, -Vector.X, ny, ey)
			block.append("")

			# Top
			pos = self.zigZagLine(block, pos, sx, self.thick, -Vector.X, -Vector.Y, nx, ex)
			block.append("")

			# Right
			pos = self.zigZagLine(block, pos, sy, self.thick, -Vector.Y, Vector.X, ny, ey)
			block.append("")
			if last: break

		# Bring to safe height
		block.append(CNC.zsafe())
Esempio n. 14
0
 def create_block(self, holes, name):
     targetDepth = self.fromMm("TargetDepth")
     peck = self.fromMm("Peck")
     dwell = self["Dwell"]
     block = Block(name)
     holesCount = 0
     for bid in holes:
         for xH, yH, zH in bid:
             holesCount += 1
             block.append(CNC.zsafe())
             block.append(CNC.grapid(xH, yH))
             if (peck != 0):
                 z = 0
                 while z > targetDepth:
                     z = max(z - peck, targetDepth)
                     block.append(CNC.zenter(zH + z))
                     block.append(CNC.zsafe())
             block.append(CNC.zenter(zH + targetDepth))
             #dwell time only on last pass
             if dwell != 0:
                 block.append(CNC.gcode(4, [("P", dwell)]))
     #Gcode Zsafe on finish
     block.append(CNC.zsafe())
     return (block, holesCount)
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
		for bid in holes:
			for xH,yH,zH in bid:
				holesCount += 1
				block.append(CNC.zsafe())
				block.append(CNC.grapid(xH,yH))
				if (peck != 0) :
					z = 0
					while z > targetDepth:
						z = max(z-peck, targetDepth)
						block.append(CNC.zenter(zH + z))
						block.append(CNC.zsafe())
				block.append(CNC.zenter(zH + targetDepth))
				#dwell time only on last pass
				if dwell != 0:
					block.append(CNC.gcode(4, [("P",dwell)]))
		#Gcode Zsafe on finish
		block.append(CNC.zsafe())
		return (block,holesCount)
Esempio n. 16
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. 17
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. 18
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. 19
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. 20
0
	def execute(self, app):
		try:
			import midiparser as midiparser
		except:
			app.setStatus(_("Error: This plugin requires midiparser.py"))
			return

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

		fileName = self["File"]

		x=0.0
		y=0.0
		z=0.0

		x_dir=1.0;
		y_dir=1.0;
		z_dir=1.0;

		# List of MIDI channels (instruments) to import.
		# Channel 10 is percussion, so better to omit it
		channels = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] 

		axes = self["AxisUsed"]
		active_axes = len(axes)

		transpose = (0,0,0)
		ppu = [ 200, 200, 200 ]
		ppu[0] = self["ppu_X"]
		ppu[1] = self["ppu_X"]
		ppu[2] = self["ppu_X"]

		safemin = [ 0, 0, 0 ]
		safemax = [ 100, 100, 50 ]
		safemax[0] = self["max_X"]
		safemax[1] = self["max_Y"]
		safemax[2] = self["max_Z"]

		try:
			midi = midiparser.File(fileName)
		except:
			app.setStatus(_("Error: Sorry can't parse the Midi file."))
			return

		noteEventList=[]
		all_channels=set()

		for track in midi.tracks:
			#channels=set()
			for event in track.events:
				if event.type == midiparser.meta.SetTempo:
					tempo=event.detail.tempo

				# filter undesired instruments
				if ((event.type == midiparser.voice.NoteOn) and (event.channel in channels)):

					if event.channel not in channels:
						channels.add(event.channel)

					# NB: looks like some use "note on (vel 0)" as equivalent to note off, so check for vel=0 here and treat it as a note-off.
					if event.detail.velocity > 0:
						noteEventList.append([event.absolute, 1, event.detail.note_no, event.detail.velocity])
					else:
						noteEventList.append([event.absolute, 0, event.detail.note_no, event.detail.velocity])

				if (event.type == midiparser.voice.NoteOff) and (event.channel in channels):
					if event.channel not in channels:
						channels.add(event.channel)
					noteEventList.append([event.absolute, 0, event.detail.note_no, event.detail.velocity])

			# Finished with this track
			if len(channels) > 0:
				msg=', ' . join(['%2d' % ch for ch in sorted(channels)])
				#print 'Processed track %d, containing channels numbered: [%s ]' % (track.number, msg)
				all_channels = all_channels.union(channels)

		# List all channels encountered
		if len(all_channels) > 0:
			msg=', ' . join(['%2d' % ch for ch in sorted(all_channels)])
			#print 'The file as a whole contains channels numbered: [%s ]' % msg

		# We now have entire file's notes with abs time from all channels
		# We don't care which channel/voice is which, but we do care about having all the notes in order
		# so sort event list by abstime to dechannelify

		noteEventList.sort()
		# print noteEventList
		# print len(noteEventList)

		last_time=-0
		active_notes={} # make this a dict so we can add and remove notes by name

		# Start the output
		#Init blocks
		blocks = []
		block = Block(self.name)
		block.append("(Midi2CNC)")
		block.append("(Midi:%s)" % fileName)
		block.append(CNC.zsafe())
		block.append(CNC.grapid(0,0))
		block.append(CNC.zenter(0))

		for note in noteEventList:
			# note[timestamp, note off/note on, note_no, velocity]
			if last_time < note[0]:

				freq_xyz=[0,0,0]
				feed_xyz=[0,0,0]
				distance_xyz=[0,0,0]
				duration=0

				# "i" ranges from 0 to "the number of active notes *or* the number of active axes,
				# whichever is LOWER". Note that the range operator stops
				# short of the maximum, so this means 0 to 2 at most for a 3-axis machine.
				# E.g. only look for the first few active notes to play despite what
				# is going on in the actual score.

				for i in range(0, min(len(active_notes.values()), active_axes)):

					# Which axis are should we be writing to?
					#
					j = self.axes_dict.get(axes)[i]

					# Debug
					# print"Axes %s: item %d is %d" % (axes_dict.get(args.axes), i, j)

					# Sound higher pitched notes first by sorting by pitch then indexing by axis
					#
					nownote=sorted(active_notes.values(), reverse=True)[i]

					# MIDI note 69	 = A4(440Hz)
					# 2 to the power (69-69) / 12 * 440 = A4 440Hz
					# 2 to the power (64-69) / 12 * 440 = E4 329.627Hz
					#
					freq_xyz[j] = pow(2.0, (nownote-69 + transpose[j])/12.0)*440.0

					# Here is where we need smart per-axis feed conversions
					# to enable use of X/Y *and* Z on a Makerbot
					#
					# feed_xyz[0] = X; feed_xyz[1] = Y; feed_xyz[2] = Z;
					#
					# Feed rate is expressed in mm / minutes so 60 times
					# scaling factor is required.

					feed_xyz[j] = ( freq_xyz[j] * 60.0 ) / ppu[j]

					# Get the duration in seconds from the MIDI values in divisions, at the given tempo
					duration = ( ( ( note[0] - last_time ) + 0.0 ) / ( midi.division + 0.0 ) * ( tempo / 1000000.0 ) )

					# Get the actual relative distance travelled per axis in mm
					distance_xyz[j] = ( feed_xyz[j] * duration ) / 60.0

				# Now that axes can be addressed in any order, need to make sure
				# that all of them are silent before declaring a rest is due.
				if distance_xyz[0] + distance_xyz[1] + distance_xyz[2] > 0:
					# At least one axis is playing, so process the note into
					# movements
					combined_feedrate = math.sqrt(feed_xyz[0]**2 + feed_xyz[1]**2 + feed_xyz[2]**2)

					# Turn around BEFORE crossing the limits of the
					# safe working envelope
					if self.reached_limit( x, distance_xyz[0], x_dir, safemin[0], safemax[0] ):
						x_dir = x_dir * -1
					x = (x + (distance_xyz[0] * x_dir))

					if self.reached_limit( y, distance_xyz[1], y_dir, safemin[1], safemax[1] ):
						y_dir = y_dir * -1
					y = (y + (distance_xyz[1] * y_dir))

					if self.reached_limit( z, distance_xyz[2], z_dir, safemin[2], safemax[2] ):
						z_dir = z_dir * -1
					z = (z + (distance_xyz[2] * z_dir))

					v = (x,y,z)
					block.append(CNC.glinev(1,v,combined_feedrate))

				else:
					# Handle 'rests' in addition to notes.
					duration = (((note[0]-last_time)+0.0)/(midi.division+0.0)) * (tempo/1000000.0)
					block.append(CNC.gcode(4, [("P",duration)]))

				# finally, set this absolute time as the new starting time
				last_time = note[0]

			if note[1]==1: # Note on
				if active_notes.has_key(note[2]):
					pass
				else:
					# key and value are the same, but we don't really care.
					active_notes[note[2]]=note[2]
			elif note[1]==0: # Note off
				if(active_notes.has_key(note[2])):
					active_notes.pop(note[2])

		blocks.append(block)
		active = app.activeBlock()
		if active==0: active=1
		app.gcode.insBlocks(active, blocks, "Midi2CNC")
		app.refresh()
		app.setStatus(_("Generated Midi2CNC, ready to play?"))
Esempio n. 21
0
    def execute(self, app):
        #Get inputs
        holesDistance = self.fromMm("HolesDistance")
        targetDepth = self.fromMm("TargetDepth")
        peck = self.fromMm("Peck")
        dwell = self["Dwell"]

        zSafe = CNC.vars["safe"]

        #Check inputs
        if holesDistance <= 0:
            app.setStatus(_("Driller abort: Distance must be > 0"))
            return

        if peck < 0:
            app.setStatus(_("Driller abort: Peck must be >= 0"))
            return

        if dwell < 0:
            app.setStatus(
                _("Driller abort: Dwell time >= 0, here time runs only forward!"
                  ))
            return

        # Get selected blocks from editor
        selBlocks = app.editor.getSelectedBlocks()
        if not selBlocks:
            app.editor.selectAll()
            selBlocks = app.editor.getSelectedBlocks()

        if not selBlocks:
            app.setStatus(_("Driller abort: Please select some path"))
            return

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

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

            #Summ all path length
            fullPathLength = 0.0
            for s in bidSegment:
                fullPathLength += s[3]

            #Calc rest
            holes = fullPathLength // holesDistance
            rest = fullPathLength - (holesDistance * (holes))
            #Travel along the path
            elapsedLength = rest / 2.0  #equaly distribute rest, as option???
            bidHoles = []
            while elapsedLength <= fullPathLength:
                #Search best segment to apply line interpolation
                bestSegment = bidSegment[0]
                segmentsSum = 0.0
                perc = 0.0
                for s in bidSegment:
                    bestSegment = s
                    segmentLength = bestSegment[3]
                    perc = (elapsedLength - segmentsSum) / segmentLength
                    segmentsSum += segmentLength
                    if segmentsSum > elapsedLength: break

                #Fist point
                x1 = bestSegment[0][0]
                y1 = bestSegment[0][1]
                z1 = bestSegment[0][2]
                #Last point
                x2 = bestSegment[1][0]
                y2 = bestSegment[1][1]
                z2 = bestSegment[1][2]

                #Check if segment is not excluded
                if not bestSegment[2]:
                    newHolePoint = (x1 + perc * (x2 - x1),
                                    y1 + perc * (y2 - y1),
                                    z1 + perc * (z2 - z1))
                    bidHoles.append(newHolePoint)

                #Go to next hole
                elapsedLength += holesDistance

            #Add bidHoles to allHoles
            allHoles.append(bidHoles)

        #Write gcommands from allSegments to the drill block
        n = self["name"]
        if not n or n == "default": n = "Driller"
        blocks = []
        block = Block(self.name)

        holesCount = 0
        for bid in allHoles:

            for xH, yH, zH in bid:
                holesCount += 1
                block.append(CNC.grapid(None, None, zH + zSafe))
                block.append(CNC.grapid(xH, yH))
                if (peck != 0):
                    z = 0
                    while z > targetDepth:
                        z = max(z - peck, targetDepth)
                        block.append(CNC.zenter(zH + z))
                        block.append(CNC.grapid(None, None, zH + zSafe))
                block.append(CNC.zenter(zH + targetDepth))
                #dwell time only on last pass
                if dwell != 0:
                    block.append(CNC.gcode(4, [("P", dwell)]))

        #Gcode Zsafe on finish
        block.append(CNC.zsafe())
        blocks.append(block)

        #Insert created block
        active = app.activeBlock()
        if active == 0: active = 1
        app.gcode.insBlocks(active, blocks, "Driller")
        app.refresh()
        app.setStatus(_("Generated Driller: %d holes") % holesCount)
Esempio n. 22
0
    def execute(self, app):
        try:
            import midiparser as midiparser
        except:
            app.setStatus(_("Error: This plugin requires midiparser.py"))
            return

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

        fileName = self["File"]

        x = 0.0
        y = 0.0
        z = 0.0

        x_dir = 1.0
        y_dir = 1.0
        z_dir = 1.0

        # List of MIDI channels (instruments) to import.
        # Channel 10 is percussion, so better to omit it
        channels = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]

        axes = self["AxisUsed"]
        active_axes = len(axes)

        transpose = (0, 0, 0)
        ppu = [200, 200, 200]
        ppu[0] = self["ppu_X"]
        ppu[1] = self["ppu_X"]
        ppu[2] = self["ppu_X"]

        safemin = [0, 0, 0]
        safemax = [100, 100, 50]
        safemax[0] = self["max_X"]
        safemax[1] = self["max_Y"]
        safemax[2] = self["max_Z"]

        try:
            midi = midiparser.File(fileName)
        except:
            app.setStatus(_("Error: Sorry can't parse the Midi file."))
            return

        noteEventList = []
        all_channels = set()

        for track in midi.tracks:
            #channels=set()
            for event in track.events:
                if event.type == midiparser.meta.SetTempo:
                    tempo = event.detail.tempo

                # filter undesired instruments
                if ((event.type == midiparser.voice.NoteOn)
                        and (event.channel in channels)):

                    if event.channel not in channels:
                        channels.add(event.channel)

                    # NB: looks like some use "note on (vel 0)" as equivalent to note off, so check for vel=0 here and treat it as a note-off.
                    if event.detail.velocity > 0:
                        noteEventList.append([
                            event.absolute, 1, event.detail.note_no,
                            event.detail.velocity
                        ])
                    else:
                        noteEventList.append([
                            event.absolute, 0, event.detail.note_no,
                            event.detail.velocity
                        ])

                if (event.type == midiparser.voice.NoteOff) and (event.channel
                                                                 in channels):
                    if event.channel not in channels:
                        channels.add(event.channel)
                    noteEventList.append([
                        event.absolute, 0, event.detail.note_no,
                        event.detail.velocity
                    ])

            # Finished with this track
            if len(channels) > 0:
                msg = ', '.join(['%2d' % ch for ch in sorted(channels)])
                #print 'Processed track %d, containing channels numbered: [%s ]' % (track.number, msg)
                all_channels = all_channels.union(channels)

        # List all channels encountered
        if len(all_channels) > 0:
            msg = ', '.join(['%2d' % ch for ch in sorted(all_channels)])
            #print 'The file as a whole contains channels numbered: [%s ]' % msg

        # We now have entire file's notes with abs time from all channels
        # We don't care which channel/voice is which, but we do care about having all the notes in order
        # so sort event list by abstime to dechannelify

        noteEventList.sort()
        # print noteEventList
        # print len(noteEventList)

        last_time = -0
        active_notes = {
        }  # make this a dict so we can add and remove notes by name

        # Start the output
        #Init blocks
        blocks = []
        block = Block(self.name)
        block.append("(Midi2CNC)")
        block.append("(Midi:%s)" % fileName)
        block.append(CNC.zsafe())
        block.append(CNC.grapid(0, 0))
        block.append(CNC.zenter(0))

        for note in noteEventList:
            # note[timestamp, note off/note on, note_no, velocity]
            if last_time < note[0]:

                freq_xyz = [0, 0, 0]
                feed_xyz = [0, 0, 0]
                distance_xyz = [0, 0, 0]
                duration = 0

                # "i" ranges from 0 to "the number of active notes *or* the number of active axes,
                # whichever is LOWER". Note that the range operator stops
                # short of the maximum, so this means 0 to 2 at most for a 3-axis machine.
                # E.g. only look for the first few active notes to play despite what
                # is going on in the actual score.

                for i in range(0, min(len(active_notes.values()),
                                      active_axes)):

                    # Which axis are should we be writing to?
                    #
                    j = self.axes_dict.get(axes)[i]

                    # Debug
                    # print"Axes %s: item %d is %d" % (axes_dict.get(args.axes), i, j)

                    # Sound higher pitched notes first by sorting by pitch then indexing by axis
                    #
                    nownote = sorted(active_notes.values(), reverse=True)[i]

                    # MIDI note 69	 = A4(440Hz)
                    # 2 to the power (69-69) / 12 * 440 = A4 440Hz
                    # 2 to the power (64-69) / 12 * 440 = E4 329.627Hz
                    #
                    freq_xyz[j] = pow(
                        2.0, (nownote - 69 + transpose[j]) / 12.0) * 440.0

                    # Here is where we need smart per-axis feed conversions
                    # to enable use of X/Y *and* Z on a Makerbot
                    #
                    # feed_xyz[0] = X; feed_xyz[1] = Y; feed_xyz[2] = Z;
                    #
                    # Feed rate is expressed in mm / minutes so 60 times
                    # scaling factor is required.

                    feed_xyz[j] = (freq_xyz[j] * 60.0) / ppu[j]

                    # Get the duration in seconds from the MIDI values in divisions, at the given tempo
                    duration = (((note[0] - last_time) + 0.0) /
                                (midi.division + 0.0) * (tempo / 1000000.0))

                    # Get the actual relative distance travelled per axis in mm
                    distance_xyz[j] = (feed_xyz[j] * duration) / 60.0

                # Now that axes can be addressed in any order, need to make sure
                # that all of them are silent before declaring a rest is due.
                if distance_xyz[0] + distance_xyz[1] + distance_xyz[2] > 0:
                    # At least one axis is playing, so process the note into
                    # movements
                    combined_feedrate = math.sqrt(feed_xyz[0]**2 +
                                                  feed_xyz[1]**2 +
                                                  feed_xyz[2]**2)

                    # Turn around BEFORE crossing the limits of the
                    # safe working envelope
                    if self.reached_limit(x, distance_xyz[0], x_dir,
                                          safemin[0], safemax[0]):
                        x_dir = x_dir * -1
                    x = (x + (distance_xyz[0] * x_dir))

                    if self.reached_limit(y, distance_xyz[1], y_dir,
                                          safemin[1], safemax[1]):
                        y_dir = y_dir * -1
                    y = (y + (distance_xyz[1] * y_dir))

                    if self.reached_limit(z, distance_xyz[2], z_dir,
                                          safemin[2], safemax[2]):
                        z_dir = z_dir * -1
                    z = (z + (distance_xyz[2] * z_dir))

                    v = (x, y, z)
                    block.append(CNC.glinev(1, v, combined_feedrate))

                else:
                    # Handle 'rests' in addition to notes.
                    duration = (((note[0] - last_time) + 0.0) /
                                (midi.division + 0.0)) * (tempo / 1000000.0)
                    block.append(CNC.gcode(4, [("P", duration)]))

                # finally, set this absolute time as the new starting time
                last_time = note[0]

            if note[1] == 1:  # Note on
                if active_notes.has_key(note[2]):
                    pass
                else:
                    # key and value are the same, but we don't really care.
                    active_notes[note[2]] = note[2]
            elif note[1] == 0:  # Note off
                if (active_notes.has_key(note[2])):
                    active_notes.pop(note[2])

        blocks.append(block)
        active = app.activeBlock()
        if active == 0: active = 1
        app.gcode.insBlocks(active, blocks, "Midi2CNC")
        app.refresh()
        app.setStatus(_("Generated Midi2CNC, ready to play?"))
Esempio n. 23
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. 24
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. 25
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. 26
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. 27
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. 28
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. 29
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. 30
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. 31
0
	def execute(self, app):
		#Get inputs
		holesDistance = self.fromMm("HolesDistance")
		targetDepth = self.fromMm("TargetDepth")
		peck = self.fromMm("Peck")
		dwell = self["Dwell"]

		zSafe = CNC.vars["safe"]

		#Check inputs
		if holesDistance <=0:
			app.setStatus(_("Driller abort: Distance must be > 0"))
			return

		if peck <0:
			app.setStatus(_("Driller abort: Peck must be >= 0"))
			return

		if dwell <0:
			app.setStatus(_("Driller abort: Dwell time >= 0, here time runs only forward!"))
			return

		# Get selected blocks from editor
		selBlocks = app.editor.getSelectedBlocks()
		if not selBlocks:
			app.editor.selectAll()
			selBlocks = app.editor.getSelectedBlocks()

		if not selBlocks:
			app.setStatus(_("Driller abort: Please select some path"))
			return

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

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

			#Summ all path length
			fullPathLength = 0.0
			for s in bidSegment:
				fullPathLength += s[3]

			#Calc rest
			holes = fullPathLength // holesDistance
			rest = fullPathLength - (holesDistance * (holes))
			#Travel along the path
			elapsedLength = rest / 2.0 #equaly distribute rest, as option???
			bidHoles = []
			while elapsedLength <= fullPathLength:
				#Search best segment to apply line interpolation
				bestSegment = bidSegment[0]
				segmentsSum = 0.0
				perc = 0.0
				for s in bidSegment:
					bestSegment = s
					segmentLength = bestSegment[3]
					perc = (elapsedLength-segmentsSum) / segmentLength
					segmentsSum += segmentLength
					if segmentsSum > elapsedLength : break

				#Fist point
				x1 = bestSegment[0][0]
				y1 = bestSegment[0][1]
				z1 = bestSegment[0][2]
				#Last point
				x2 = bestSegment[1][0]
				y2 = bestSegment[1][1]
				z2 = bestSegment[1][2]

				#Check if segment is not excluded
				if not bestSegment[2]:
					newHolePoint = (x1 + perc*(x2-x1) ,
						y1 + perc*(y2-y1),
						z1 + perc*(z2-z1))
					bidHoles.append(newHolePoint)

				#Go to next hole
				elapsedLength += holesDistance

			#Add bidHoles to allHoles
			allHoles.append(bidHoles)

		#Write gcommands from allSegments to the drill block
		n = self["name"]
		if not n or n=="default": n="Driller"
		blocks = []
		block = Block(self.name)

		holesCount = 0
		for bid in allHoles:

			for xH,yH,zH in bid:
				holesCount += 1
				block.append(CNC.grapid(None,None,zH + zSafe))
				block.append(CNC.grapid(xH,yH))
				if (peck != 0) :
					z = 0
					while z > targetDepth:
							z = max(z-peck, targetDepth)
							block.append(CNC.zenter(zH + z))
							block.append(CNC.grapid(None,None,zH + zSafe))
				block.append(CNC.zenter(zH + targetDepth))
				#dwell time only on last pass
				if dwell != 0:
						block.append(CNC.gcode(4, [("P",dwell)]))

		#Gcode Zsafe on finish
		block.append(CNC.zsafe())
		blocks.append(block)

		#Insert created block
		active = app.activeBlock()
		if active==0: active=1
		app.gcode.insBlocks(active, blocks, "Driller")
		app.refresh()
		app.setStatus(_("Generated Driller: %d holes")%holesCount)
Esempio n. 32
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. 33
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. 34
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. 35
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. 36
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. 37
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