Example #1
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))))
Example #2
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
Example #3
0
    def execute(self, app):

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

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

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

        filename = self["File"]

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

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

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

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

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

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

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

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

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

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

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

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

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

        #Select all blocks
        app.editor.selectAll()

        paths_base = []
        paths_isl = []

        points = []

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

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

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

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

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

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

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

        #print(matrix)

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

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

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

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

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

###SORTING POINTS END###

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

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

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

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

        app.editor.disable()

        for block in blocks:
            block.enable = 1

        #app.editor.enable()
        #app.editor.unselectAll()
        app.refresh()
        app.setStatus(_("Generated Line to Line Burning"))
Example #4
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
Example #5
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
Example #6
0
File: gear.py Project: 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
Example #7
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
Example #8
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))))
Example #9
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))
Example #10
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))