def calc(self,x,y,depth,peck,dwell,drillFeed,safeZforG0): self.safeZforG0 =float(abs(safeZforG0)) peck=abs(float(peck)) currentz=0.0 self.blocks = [] self.block = Block(self.name) self.block.append(CNC.grapid(x=x,y=y)) self.block.append(CNC.grapid(z=CNC.vars["safe"])) self.accelerateIfNeeded(0.0,drillFeed) self.block.append("(entered)") while(currentz>depth): currentz-=peck if currentz < depth: currentz = depth kwargs={"f":float(drillFeed)} self.block.append(CNC.gline(None,None,float(currentz),**kwargs)) if self.safeZforG0 >0: self.block.append(CNC.grapid(z=0.0+self.safeZforG0)) else : self.block.append(CNC.grapid(z=CNC.vars["safe"])) self.block.append("g4 %s"%(CNC.fmt("p",float(dwell)))) if currentz > depth: self.accelerateIfNeeded(currentz,drillFeed) self.block.append("(exiting)") self.block.append(CNC.grapid(z=CNC.vars["safe"])) self.blocks.append(self.block) return self.blocks
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)
def appendCross(block): block.append("m5") block.append(CNC.grapid(x=x0, y=y0 + marksizehalf, f=movefeed)) block.append(self.getPowerLine(app)) block.append(CNC.gline(y=y0 - marksizehalf, f=drawfeed)) block.append("m5") block.append(CNC.grapid(x=x0 + marksizehalf, y=y0, f=movefeed)) block.append(self.getPowerLine(app)) block.append(CNC.gline(x=x0 - marksizehalf, f=drawfeed)) block.append("m5")
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
def appendCross45(block): msh = marksizehalf * self.sin45 block.append("m5") block.append(CNC.grapid(x=x0 - msh, y=y0 + msh, f=movefeed)) block.append(self.getPowerLine(app)) block.append(CNC.gline(x=x0 + msh, y=y0 - msh, f=drawfeed)) block.append("m5") block.append(CNC.grapid(x=x0 + msh, y=y0 + msh, f=movefeed)) block.append(self.getPowerLine(app)) block.append(CNC.gline(x=x0 - msh, y=y0 - msh, f=drawfeed)) block.append("m5")
def calc(self, xstart, ystart, xend, yend, radius, cw): self.Points = [] self.corners = [ min(float(xstart), float(xend)), min(float(ystart), float(yend)), max(float(xstart), float(xend)), max(float(ystart), float(yend)), ] xmin, ymin, xmax, ymax = self.corners[0], self.corners[ 1], self.corners[2], self.corners[3] r = min(radius, (xmax - xmin) / 2, (ymax - ymin) / 2) blocks = [] block = Block(self.name) block.append(CNC.grapid(x=xmin, y=ymin + r)) block.append(CNC.grapid(z=0.0)) block.append("(entered)") if cw: block.append(CNC.gline(x=xmin, y=ymax - r)) if r > 0: block.append(CNC.garc(2, x=xmin + r, y=ymax, i=r, j=0)) if (xmax - xmin) > 2 * r: block.append(CNC.gline(x=xmax - r, y=ymax)) if r > 0: block.append(CNC.garc(2, x=xmax, y=ymax - r, i=0, j=-r)) if (ymax - ymin) > 2 * r: block.append(CNC.gline(x=xmax, y=ymin + r)) if r > 0: block.append(CNC.garc(2, x=xmax - r, y=ymin, i=-r, j=0)) if (xmax - xmin) > 2 * r: block.append(CNC.gline(x=xmin + r, y=ymin)) if r > 0: block.append(CNC.garc(2, x=xmin, y=ymin + r, i=0, j=r)) else: if r > 0: block.append(CNC.garc(3, x=xmin + r, y=ymin, i=r, j=0)) if (xmax - xmin) > 2 * r: block.append(CNC.gline(x=xmax - r, y=ymin)) if r > 0: block.append(CNC.garc(3, x=xmax, y=ymin + r, i=0, j=r)) if (ymax - ymin) > 2 * r: block.append(CNC.gline(x=xmax, y=ymax - r)) if r > 0: block.append(CNC.garc(3, x=xmax - r, y=ymax, i=-r, j=0)) if (xmax - xmin) > 2 * r: block.append(CNC.gline(x=xmin + r, y=ymax)) if r > 0: block.append(CNC.garc(3, x=xmin, y=ymax - r, i=0, j=-r)) if (ymax - ymin) > 2 * r: block.append(CNC.gline(x=xmin, y=ymin + r)) block.append("(exiting)") block.append(CNC.grapid(z=CNC.vars["safe"])) blocks.append(block) return blocks
def appendSpikes45(block): sinSpike = math.sin(math.atan(1.0 / math.sqrt(3))) cosSpike = math.cos(math.atan(1.0 / math.sqrt(3))) block.append("m5") block.append(CNC.grapid(x=x0, y=y0, f=movefeed)) block.append(self.getPowerLine(app)) block.append( CNC.gline(x=x0 + marksizehalf * sinSpike, y=y0 - marksizehalf * cosSpike, f=drawfeed)) block.append( CNC.gline(x=x0 + marksizehalf * cosSpike, y=y0 - marksizehalf * sinSpike, f=drawfeed)) block.append( CNC.gline(x=x0 - marksizehalf * cosSpike, y=y0 + marksizehalf * sinSpike, f=drawfeed)) block.append( CNC.gline(x=x0 - marksizehalf * sinSpike, y=y0 + marksizehalf * cosSpike, f=drawfeed)) block.append(CNC.gline(x=x0, y=y0, f=drawfeed)) block.append( CNC.gline(x=x0 - marksizehalf * sinSpike, y=y0 - marksizehalf * cosSpike, f=drawfeed)) block.append( CNC.gline(x=x0 - marksizehalf * cosSpike, y=y0 - marksizehalf * sinSpike, f=drawfeed)) block.append( CNC.gline(x=x0 + marksizehalf * cosSpike, y=y0 + marksizehalf * sinSpike, f=drawfeed)) block.append( CNC.gline(x=x0 + marksizehalf * sinSpike, y=y0 + marksizehalf * cosSpike, f=drawfeed)) block.append(CNC.gline(x=x0, y=y0, f=drawfeed)) block.append("m5") block.append( CNC.grapid(x=x0 + marksizehalf / 2, y=y0 + marksizehalf / 2, f=movefeed)) block.append(self.getPowerLine(app)) block.append(CNC.gline(x=x0 - marksizehalf / 2, f=drawfeed)) block.append(CNC.gline(y=y0 - marksizehalf / 2, f=drawfeed)) block.append(CNC.gline(x=x0 + marksizehalf / 2, f=drawfeed)) block.append(CNC.gline(y=y0 + marksizehalf / 2, f=drawfeed)) block.append("m5")
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
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
def calc(self, xstart, ystart, xend, yend): points = [] points.append(Vector(xstart, ystart)) points.append(Vector(xend, yend)) first = points[0] last = points[1] blocks = [] block = Block(self.name) block.append(CNC.grapid(first.x(), first.y())) block.append(CNC.grapid(z=0.0)) block.append("(entered)") block.append(CNC.gline(last.x(), last.y())) block.append("(exiting)") block.append(CNC.grapid(z=CNC.vars["safe"])) blocks.append(block) return blocks
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
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)
def appendBurn(self, app, block): x0 = self.fromMm("PosX") y0 = self.fromMm("PosY") movefeed = app.cnc["cutfeed"] burntime = self["Burn time"] burnpower = self["Burn power"] block.append(CNC.grapid(x=x0, y=y0)) block.append("g1 m3 %s" % (CNC.fmt('s', burnpower))) block.append("g4 %s" % (CNC.fmt('p', burntime))) block.append("m5")
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
def appendCircle(block): block.append("m5") block.append(CNC.grapid(x=x0, y=y0 + marksizehalf / 2, f=movefeed)) block.append(self.getPowerLine(app)) block.append( CNC.garc(2, x=x0, y=y0 + marksizehalf / 2, j=-marksizehalf / 2, i=0, f=drawfeed)) block.append("m5")
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))
def calc(self, xcenter, ycenter, radius, startangle, endangle): self.Points = [] xcenter, ycenter, radius, startangle, endangle = float(xcenter), float( ycenter), abs(float(radius)), float(startangle), float(endangle) xstart = xcenter + radius * math.cos(startangle * math.pi / 180.0) xend = xcenter + radius * math.cos(endangle * math.pi / 180.0) ystart = ycenter + radius * math.sin(startangle * math.pi / 180.0) yend = ycenter + radius * math.sin(endangle * math.pi / 180.0) i = xcenter - xstart j = ycenter - ystart blocks = [] block = Block(self.name) block.append(CNC.grapid(x=xstart, y=ystart)) block.append(CNC.grapid(z=0.0)) block.append("(entered)") if startangle < endangle: direction = 3 else: direction = 2 block.append(CNC.garc(direction, x=xend, y=yend, i=i, j=j)) block.append("(exiting)") block.append(CNC.grapid(z=CNC.vars["safe"])) blocks.append(block) return blocks
def appendSpikes45(block): sinSpike = math.sin(math.atan(1.0 / math.sqrt(3))) cosSpike = math.cos(math.atan(1.0 / math.sqrt(3))) block.append("m5") block.append(CNC.grapid(x=x0, y=y0, f=movefeed)) block.append(self.getPowerLine(app)) block.append(CNC.gline(x=x0 + marksizehalf * sinSpike, y=y0 - marksizehalf * cosSpike, f=drawfeed)) block.append(CNC.gline(x=x0 + marksizehalf * cosSpike, y=y0 - marksizehalf * sinSpike, f=drawfeed)) block.append(CNC.gline(x=x0 - marksizehalf * cosSpike, y=y0 + marksizehalf * sinSpike, f=drawfeed)) block.append(CNC.gline(x=x0 - marksizehalf * sinSpike, y=y0 + marksizehalf * cosSpike, f=drawfeed)) block.append(CNC.gline(x=x0, y=y0, f=drawfeed)) block.append(CNC.gline(x=x0 - marksizehalf * sinSpike, y=y0 - marksizehalf * cosSpike, f=drawfeed)) block.append(CNC.gline(x=x0 - marksizehalf * cosSpike, y=y0 - marksizehalf * sinSpike, f=drawfeed)) block.append(CNC.gline(x=x0 + marksizehalf * cosSpike, y=y0 + marksizehalf * sinSpike, f=drawfeed)) block.append(CNC.gline(x=x0 + marksizehalf * sinSpike, y=y0 + marksizehalf * cosSpike, f=drawfeed)) block.append(CNC.gline(x=x0, y=y0, f=drawfeed)) block.append("m5") block.append(CNC.grapid(x=x0 + marksizehalf / 2, y=y0 + marksizehalf / 2, f=movefeed)) block.append(self.getPowerLine(app)) block.append(CNC.gline(x=x0 - marksizehalf / 2, f=drawfeed)) block.append(CNC.gline(y=y0 - marksizehalf / 2, f=drawfeed)) block.append(CNC.gline(x=x0 + marksizehalf / 2, f=drawfeed)) block.append(CNC.gline(y=y0 + marksizehalf / 2, f=drawfeed)) block.append("m5")
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
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
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)
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)
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
def execute(self, app): # ae = self.fromMm("ae") if self["splicesteps"] =="" or self["splicesteps"]<4: steps=4/(2*pi) else: steps=self["splicesteps"]/(2*pi) # manualsetting = self["manualsetting"] manualsetting = 1 #=========== Converted to comment and changed for current compatibility ============================== # cutradius = CNC.vars["trochcutdiam"]/2.0 cutradius = self["diam"]/2.0 # cutradius = CNC.vars["trochcutdiam"]/2.0 #========================================================================================= zfeed = CNC.vars["cutfeedz"] feed =CNC.vars["cutfeed"] minimfeed =CNC.vars["cutfeed"] if manualsetting: if self["diam"]: cutradius = self["diam"]/2.0 if self["zfeed"] and self["zfeed"]!="": zfeed = self["zfeed"] # if self["minimfeed"] and self["minimfeed"]!="": # minimfeed = min (self["minimfeed"],feed) if self["feed"] and self["feed"]!="": feed = self["feed"] if self["endmill"]: self.master["endmill"].makeCurrent(self["endmill"]) # radius = CNC.vars["cutdiam"]/2.0 # radius = self["diam"]/2.0 toolRadius = CNC.vars["diameter"]/2.0 radius = max(0,cutradius-toolRadius) oldradius=radius #----------------------------------------------------------- # helicalRadius = self["helicalDiam"]/2.0 # if helicalRadius=="": # helicalRadius=radius # else: # helicalRadius=max(0,helicalRadius- toolRadius) helicalRadius=radius #----------------------------------------------------------- # helicalRadius=min(0.99*toolRadius,helicalRadius) # if radius!=0: # helicalRadius= min(helicalRadius,radius) helicalPerimeter=pi*2.0*helicalRadius # helicalangle = self["helicalangle"] # if helicalangle>89.5: # helicalangle=89.5 # if helicalangle<0.01: # helicalangle=0.01 # downPecking=helicalPerimeter*tan(radians(helicalangle)) cw = self["cw"] surface = CNC.vars["surface"] #=========== Converted to comment and changed for current compatibility ============================== # zbeforecontact=surface+CNC.vars["zretract"] # zbeforecontact=surface+CNC.vars["zretract"] # hardcrust = surface - CNC.vars["hardcrust"] # feedbeforecontact = CNC.vars["feedbeforecontact"]/100.0 # hardcrustfeed = CNC.vars["hardcrustfeed"]/100.0 zbeforecontact=surface zbeforecontact=surface hardcrust = surface feedbeforecontact = zfeed hardcrustfeed = feed #===================================================================================================== t_splice = self["TypeSplice"] dtadaptative = 0.0001 adaptativepolice=0 # minimradius = min(radius, toolRadius*self["MinTrochDiam"]/(100)) # minimradius = min(radius, toolRadius*self["MinTrochDiam"]/(100)) # minimradius = min(radius, toolRadius*CNC.vars["mintrochdiam"]/(100)) atot = self.fromMm("ae") # spiral_twists=(radius-helicalRadius)/atot#<<spiral ae smaller than ae (aprox 50%) # if (radius-helicalRadius)%atot: spiral_twists=1+(radius-helicalRadius)//atot spiral_twists=ceil(radius-helicalRadius)/atot#<<spiral ae smaller than ae (aprox 50%) rpm = self["rpm"] downPecking=helicalPerimeter*zfeed/feed helicalangle=degrees(atan2(downPecking,helicalPerimeter)) # steps=self["splicesteps"]/2*pi # K_Z = self["K_Z"] # if K_Z == "": # K_Z = 1.0 # K_XY = self["K_XY"] # if K_XY == "": # K_XY = 1.0 # s_z = self["S_z"] # s_xy = self["S_xy"] # xyfeed = CNC.vars["cutfeed"] # zfeed *= K_Z # xyfeed *=K_XY # Get selected blocks from editor # def trochprofile_bcnc(self, cutDiam=0.0, direction=None, offset=0.0, overcut=False,adaptative=False, adaptedRadius=0.0, tooldiameter=0.0, name=None): # app.trochprofile_bcnc(trochcutdiam, direction, self["offset"], self["overcut"], self["adaptative"], cornerradius, CNC.vars["diameter"], name) #<< diameter only to information # cornerradius = (cutradius - CNC.vars["diameter"]/2.0 direction=self["direction"] if direction!="on (3d Path)": targetDepth=self["targetDepth"] depthIncrement=self["depthIncrement"] # tabsnumber=self["tabsnumber"] # tabsWidth=self["tabsWidth"] # tabsHeight=self["tabsHeight"] tabsnumber=tabsWidth=tabsHeight=0 app.trochprofile_bcnc(2*cutradius, direction,self["offset"], self["overcut"], self["adaptative"], radius, CNC.vars["diameter"],\ targetDepth, depthIncrement, tabsnumber, tabsWidth, tabsHeight) app.refresh() # app.editor.selectAll() selBlocks = app.editor.getSelectedBlocks() # if not selBlocks: # app.editor.selectAll() # selBlocks = app.editor.getSelectedBlocks() if not selBlocks: app.setStatus(_("Trochoid abort: Please select some path")) return #Check inputs if cutradius <= toolRadius: app.setStatus(_("Trochoid Cut Diameter has to be greater than End mill")) return if helicalRadius <= 0.0: app.setStatus(_("Helical Descent Diameter has to be greater than End mill")) return if feed <= 0: app.setStatus(_("Feed has to be greater than 0")) return if zfeed <= 0: app.setStatus(_("Plunge Feed has to be greater than 0")) return if minimfeed <= 0: app.setStatus(_("Minimum Adaptative Feed has to be greater than 0")) return #Get all segments from gcode allSegments = self.extractAllSegments(app,selBlocks) #Create holes locations # allHoles=[] for bidSegment in allSegments: if len(bidSegment)==0: continue blocks = [] # n = self["name"] # if not n or n=="default": n="Trochoidal_3D" # newname = Block.operationName(path.name) n="Troch3d" tr_block = Block(n) phi=oldphi=0# oldadaptativephi=0 oldsegm=[[0,0,0],[0,0,0]] # segments --------------------------------------------- for idx, segm in enumerate(bidSegment): if idx >= 0: if cw: u = 1 arc = "G2" else: u = -1 arc = "G3" # ////////////--------------------------------------------------------------------- # information: --------------------------------------------------------------------- segLength = self.calcSegmentLength(segm) # --------------------------------------------- # tr_block.append("(seg length "+str(round(segLength,4))+" )") # ----------------------------------------------------------------------------- # ////////---------------------------------------------------------------------- if idx == 0: # tr_block.append("(-------------- PARAMETERS ------------------------)") tr_block.append("(Cut diam "+str( cutradius*2 )+" (troch "+str(radius*2.0)+"+End mill "+str(toolRadius*2.0)+" ) Advance "+str(atot)+" )") # tr_block.append("(Cut diam "+str(CNC.vars["trochcutdiam"])+" (troch "+str(radius*2.0)+" + End mill " + str(toolRadius*2.0)+" ) Advance "+str(atot)+" )") # tr_block.append("(Min troch "+str(int(CNC.vars["mintrochdiam"]))+"% = "+str(minimradius*2.0)+"mm , min cut diam "+str(2*(minimradius+toolRadius))+"mm )") tr_block.append("(Feed "+str(feed)+" Plunge feed "+ str(zfeed)+" )") #tr_block.append("(Helical diam "+str(round((helicalRadius+toolRadius)*2,2))+" ( helical diam "+str(helicalRadius*2.0)+"+End mill "+str(toolRadius*2.0)+" )") tr_block.append("(Helical descent angle " + str(round(helicalangle,2)) +" cut diam " + str(round(helicalRadius*2.0,3))+" drop by lap "\ + str(round(downPecking,2)) + " )") tr_block.append("(--------------------------------------------------)") tr_block.append("(M06 T0 "+str(toolRadius*2.0)+" mm)") tr_block.append("M03") tr_block.append("S "+str(rpm)) tr_block.append("F "+str(feed)) # phi = atan2(segm[1][1]-segm[0][1], segm[1][0]-segm[0][0]) # oldphi=phi #<< declare initial angle # l = self.pol2car(radius, phi+radians(90*u)) # r = self.pol2car(radius, phi+radians(-90*u)) # B = segm[1][0],segm[1][1],segm[1][2] # bl = self.pol2car(radius, phi+radians(90*u), B) # br = self.pol2car(radius, phi+radians(-90*u), B) tr_block.append("( Seg: "+str(idx)+" length "+str(round(segLength,4))+" phi "+str(round(degrees(phi),2))+" )")#+ " oldphi "+str(round(oldphi*57.29,2))+" )") tr_block.append("(Starting point)") if (round(segm[1][1]-segm[0][1],4)==0 and round(segm[1][0]-segm[0][0],4)==0): phi=1234567890 tr_block.append("(The original first movement is vertical)") else: tr_block.append("(The original first movement is not vertical)") tr_block.append(CNC.zsafe()) # tr_block.append("g0 x "+str(B[0])+" y"+str(B[1])+" )")#" z "+str(B[2])+" )") # tr_block.append(arc+" x"+str(bl[0])+" y"+str(bl[1])+" R "+str(radius/2.0)+" z"+str(B[2])) # tr_block.append(arc+" x"+str(br[0])+" y"+str(br[1])+" i"+str(r[0]/2.0)+" j"+str(r[1]/2.0)) #<< as cutting # tr_block.append(("g1 x "+str(br[0])+" y"+str(br[1])+" z"+str(B[2]))) # tr_block.append(arc+" x"+str(bl[0])+" y"+str(bl[1])+" i"+str(l[0])+" j"+str(l[1])) # tr_block.append(arc+" x"+str(br[0])+" y"+str(br[1])+" i"+str(r[0])+" j"+str(r[1])+" z"+str(round(B[2],5))) #<< as cutting # if t_splice=="Circular both sides rectified": # tr_block.append(arc+" x"+str(bl[0])+" y"+str(bl[1])+" i"+str(-r[0])+" j"+str(-r[1])) tr_block.append("(--------------------------------------------------)") # tr_block.append(CNC.grapid(br[0],br[1],B[2])) # tr_block.append(CNC.zsafe()) #<<< Move rapid Z axis to the safe height in Stock Material # tr_block.append(CNC.zenter(surface)) # <<< TROCHOID CENTER # tr_block.append(CNC.grapid(segm[1][0],segm[1][1],segm[1][2])) # tr_block.append(CNC.zbeforecontact()) # <<< TROCHOID CENTER # tr_block.append(CNC.xyslowentersurface(0,-45.0)) # <<< TROCHOID CENTER # tr_block.append(("g0 z "+str(zbeforecontact))) # tr_block.append("( new segment begins )") # distance to trochoid center # if there is movement in xy plane phi calculate if (segm[1][1]-segm[0][1]!=0 or segm[1][0]-segm[0][0]!=0): phi = atan2(segm[1][1]-segm[0][1], segm[1][0]-segm[0][0]) # On surface # if segm[0][2]>zbeforecontact and segm[1][2]>zbeforecontact: if segm[0][2]>surface and segm[1][2]>surface: tr_block.append("(Seg: "+str(idx)+" length "+str(round(segLength,4))+" phi "+str(round(degrees(phi),2))+ " On Surface)" ) tr_block.append(CNC.grapid(segm[1][0],segm[1][1],segm[1][2])) else: tr_distance = self.center_distance(segm,atot) A = segm[0][0],segm[0][1],segm[0][2] d=segLength ae = tr_distance[4] # ////////////--------------------------------------------------------------------- # information: --------------------------------------------------------------------- adv = tr_distance[3] #<<< ap = tr_distance[2] # << =zadd # --------------------------------------------- tr_block.append("(-----------------------------------------)") control_cameback = self.came_back(segm, oldsegm) if control_cameback: tr_block.append("(-------------> Came back !! <------------- )")#+str(control_cameback)+" )") # tr_block.append("( old Ax "+str(round(oldsegm[0][0],3))+" Ay "+str(round(oldsegm[0][1],3))+" Bx "+ str(round(oldsegm[1][0],3))+" By "+ str(round(oldsegm[1][1],3))+" )") # tr_block.append("( curr Ax "+str(round(segm[0][0],3))+" Ay "+str(round(segm[0][1],3))+" Bx "+ str(round(segm[1][0],3))+" By "+ str(round(segm[1][1],3))+" )") if round(segLength,5) <= dtadaptative: adaptativepolice+=1.0 tr_block.append("(Seg "+str(idx)+" adaptativepolice " +str(adaptativepolice)+" length "+str(round(segLength,5))+" )") # /////////// Trochoid method ////////////////////////////////////////////////////////////////////////////// if adaptativepolice==0 or adaptativepolice >2.5: tr_block.append("( Seg: "+str(idx)+" phi "+str(round(degrees(phi),2))+ " oldphi "+str(round(degrees(oldphi),2))+" length "+str(round(segLength,5))+" )") tr_block.append("(ae: "+str(round(ae,5))+" dz: "+str(round(ap,4))+"adv: "+str(round(adv,4))+" )") # tr_block.append("( Bx "+str(round(segm[1][0],2))+ " By "+ str(round(segm[1][1],2))) # ----------------------------------------------------------------------------- # ////////---------------------------------------------------------------------- if control_cameback: # adaptativepolice+=0.5 B = segm[1][0],segm[1][1],segm[1][2] # tr_block.append(CNC.gline(segm[1][0],segm[1][1],segm[1][2])) t_splice="came_back" # tr_block.extend(self.trochoid(t_splice,A,B,minimradius,radius,oldphi,phi,cw)) tr_block.extend(self.trochoid(t_splice,A,B,0.0,radius,oldphi,phi,cw)) tr_block.append("F "+ str(feed)) t_splice = self["TypeSplice"] else: # from POINT A -- to ---> POINT B if segLength<=adv: tr_block.append("(Only one trochoid, oldphi "+str(round(degrees(oldphi),2))+" )") tr_block.extend(self.trochoid(t_splice,A,B,oldradius,radius,oldphi,phi,cw)) while d >adv: # first trochoid # tr_block.append("d "+ str(d)) B = A[0]+tr_distance[0], A[1]+tr_distance[1], A[2]+tr_distance[2] # intermediates points = trochoids points # tr_block.append(CNC.gline(B[0],B[1],B[2])) # <<< TROCHOID CENTER # tr_block.extend(self.trochoid(A,B,radius,phi,oldphi,cw)) tr_block.append("(distance to end segment "+str(round(d,4))+" )") tr_block.extend(self.trochoid(t_splice,A,B,oldradius,radius,oldphi,phi,cw)) A=B d-=adv oldphi=phi # last point if B[0] != segm[1][0] or B[1] != segm[1][1] or B[2] != segm[1][2]: B = segm[1][0],segm[1][1],segm[1][2] # tr_block.append(CNC.gline(B[0],B[1],B[2])) # <<< TROCHOID CENTER tr_block.append("(---last trochoid, distance to end segment "+str(round(d,4))+" ---)") tr_block.extend(self.trochoid(t_splice,A,B,oldradius,radius,phi,phi,cw)) adaptativepolice=0 # /////// Adapative method ////////////////////////////////////////////////////////////////////////////////////////////////////////// # if oldphi==3600: else: if adaptativepolice==1: #goes to de two warning movements lastphi=oldphi tr_block.append("( Alarm "+ str(adaptativepolice)+" Seg: "+str(idx)+" phi " + str(round(degrees(phi),2))\ + "oldphi "+str(round(degrees(oldphi),2))+ " )") # difangle=(phi-oldadaptativephi) # tr_block.append("(dif angle:"+str(round(difangle,4))+" )") # oldadaptativephi=oldphi=phi # round(difangle,5)==round(pi,5): elif adaptativepolice==2: phi=lastphi if control_cameback:# abs(round(difangle,6)) == (round(pi,6)): tr_block.append("(Starts adaptative trochoids"+" adaptativepolice "+str(adaptativepolice) ) adaptativepolice +=0.5 elif adaptativepolice==2.5: # tr_block.append("(-----------------------------------------)") # adaptradius=minimradius tr_block.append("(Adaptative Seg: "+str(idx)+" length "+str(round(segLength,5))+" phi "+str(round(degrees(phi),2))\ +" oldphi "+str(round(degrees(oldphi),2))+" )") # tr_block.append("( Ax "+str(round(segm[0][0],2))+ " Ay "+ str(round(segm[0][1],2))) # tr_block.append(CNC.gline(segm[1][0],segm[1][1],segm[1][2])) # from POINT A -- to ---> POINT B # if adaptativepolice==1: tr_distance = self.center_distance(segm,atot/3.0) #<<< short advanc distances A = segm[0][0],segm[0][1],segm[0][2] d=segLength ae = tr_distance[4] adv = tr_distance[3] #<<< d-=adv while d >0:#adv: # first trochoid if d!=segLength-adv: oldphi=phi # tr_block.append("d "+ str(d)) B = A[0]+tr_distance[0], A[1]+tr_distance[1], A[2]+tr_distance[2] #------------------------------ # adaptradius= a*d + minimradius # if d=0 : adaptradius=minimradius # if d=seglength : adaptradius=radius # a=(radius-minimradius)/segLength # adaptradius=a*d+minimradius a=radius/segLength adaptradius=(self.roundup(a*d,4))#+minimradius #------------------------------ if t_splice!="Splices": t_splice="Warpedarc" tr_block.append("(from trochoid distance to end segment "+str(round(d,4))+" )") tr_block.append("(adaptradius "+ str(round(adaptradius,4))+" radius " + str(radius)+" )") # tr_block.append("F "+ str(feed*adaptradius//radius)) tr_block.append("F "+ str(minimfeed+(feed-minimfeed) *adaptradius//radius)) if adaptradius>0.0: tr_block.extend(self.trochoid(t_splice,A,B,oldradius,adaptradius,oldphi,phi,cw)) else: tr_block.append("(R= "+str(adaptradius)+ "not sent )") # tr_block.append("G1 x"+str(round(B[0],4))+" y "+str(round(B[1],4))+" z "+str(round(B[2],4))) A=B d-=adv oldradius=adaptradius # oldadaptativephi=0 #REVISAR, A COMENTADO # last point # d=0 # oldradius=adaptradius # adaptradius=minimradius # if B[0] != segm[1][0] or B[1] != segm[1][1] or B[2] != segm[1][2]: # B = segm[1][0],segm[1][1],segm[1][2] # tr_block.append(CNC.gline(B[0],B[1],B[2])) # <<< TROCHOID CENTER # tr_block.append("(last trochoid, from trochoid distance to end segment "+str(round(d,4))+" )") # tr_block.append("(adaptradius "+ str(adaptradius)+" )") # tr_block.append("F "+ str(feed*adaptradius//radius)) # tr_block.extend(self.trochoid(t_splice,A,B,oldradius,adaptradius,phi,phi,cw)) adaptativepolice=0 tr_block.append("(Adaptative Completed)") tr_block.append("F "+ str(feed//3)) # if adaptativepolice>1: t_splice = self["TypeSplice"] # adaptativepolice=0 oldradius=radius oldsegm=segm oldphi=phi # /////// Vertical movement /////////////////////////////////////////////////////////////////////////////////////////////////////////////// elif idx!=0: tr_block.append("(Seg: "+str(idx)+" length "+str(round(segLength,4))+" phi "+str(round(degrees(phi),2))+" oldphi "+str(round(degrees(oldphi),2))+" )" ) tr_block.append("(Helical descent") # descent A=segm[0][0],segm[0][1],segm[0][2] if segm[0][2] > segm[1][2]: if segm[0][2] >zbeforecontact:# and segm[1][2]<=surface: if segm[1][2]<=zbeforecontact: B = segm[1][0],segm[1][1],max(segm[1][2],zbeforecontact) tr_block.append("(Rapid helical to z before contact "+"helicalRadius "+str(helicalRadius)+" )") if idx==1 and oldphi==1234567890: tr_block.append("g0 x "+str(B[0])+" y"+str(B[1])+" )")#" z "+str(B[2])+" )") tr_block.extend(self.helical(A,B,helicalRadius,phi,u)) # Instead of decreasing the speed, to avoid the jerkl, decrease the drop by lap if segm[0][2] >surface:# and segm[1][2]<=surface: if segm[1][2]<=surface: tr_block.append("(Slow helical to surface )" ) A=A[0],A[1],zbeforecontact d=A[2]-surface adv=downPecking * feedbeforecontact while d > adv: B = segm[1][0],segm[1][1],max(segm[1][2],A[2]-adv) tr_block.extend(self.helical(A,B,helicalRadius,phi,u)) A=A[0],A[1],B[2] d-=adv B = segm[1][0],segm[1][1],surface tr_block.extend(self.helical(A,B,helicalRadius,phi,u)) if segm[0][2] >hardcrust:# and segm[1][2]<=surface: if hardcrust< surface: if segm[1][2]<=hardcrust: tr_block.append("(Helical in hard crust)" ) A=A[0],A[1],surface d=A[2]-hardcrust adv=downPecking * hardcrustfeed while d > adv: B = segm[1][0],segm[1][1],max(segm[1][2],A[2]-adv) tr_block.extend(self.helical(A,B,helicalRadius,phi,u)) A=A[0],A[1],B[2] d-=adv B = segm[1][0],segm[1][1],hardcrust tr_block.extend(self.helical(A,B,helicalRadius,phi,u)) tr_block.append("(Helical to target )" ) A=A[0],A[1],hardcrust d=A[2]-segm[1][2] adv=downPecking while d > adv: B = segm[1][0],segm[1][1],A[2]-adv tr_block.extend(self.helical(A,B,helicalRadius,phi,u)) A=A[0],A[1],B[2] d-=adv B = segm[1][0],segm[1][1],segm[1][2] tr_block.extend(self.helical(A,B,helicalRadius,phi,u)) tr_block.append("(Flatten)") tr_block.extend(self.helical(B,B,helicalRadius,phi,u)) if round(helicalRadius,4)!=round(radius,4): tr_block.append("(Spiral adjustement)") # tr_block.extend(self.trochoid(t_splice,B,B,radius,helicalRadius,phi,phi+4*pi,cw)) # steps=max(1,int(steps*radius*(spiral_twists)/2.0)) # steps=min(steps, 12*spiral_twists) # steps*=spiral_twists # tr_block.append("(Spiral steps "+str(steps)+" in "+str(int((spiral_twists/2.)+1))+" twists)") # tr_block.append("(Spiral "+str(int((spiral_twists/2.)+1))+" twists)") tr_block.append("(Spiral "+str(spiral_twists)+" twists)") tr_block.extend(self.splice_generator(B,B,helicalRadius,radius,phi,phi-spiral_twists*2*pi, radians(-90),radians(-90),u,1.2*steps)) tr_block.append("(Target diameter)") # tr_block.extend(self.helical(B,B,radius,phi,u)) tr_block.extend(self.trochoid(t_splice,B,B,radius,radius,phi,phi,cw)) # ascent elif segm[1][2] > segm[0][2]: tr_block.append("(Helical rapid ascentt "+"helicalRadius "+str(helicalRadius)+" )" ) B = segm[1][0],segm[1][1],segm[1][2] tr_block.extend(self.helical(A,B,helicalRadius,phi,u)) # tr_block.append(CNC.grapid(center[0],center[1],center[2])) # tr_block.extend(CNC.grapid(center)) # end of segment # tr_block.append(CNC.gline(segm[1][0],segm[1][1],segm[1][2])) # oldsegm=segm tr_block.append("(-----------------------------------------)") tr_block.append(CNC.zsafe()) #<<< Move rapid Z axis to the safe height in Stock Material blocks.append(tr_block) self.finish_blocks(app, blocks)
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)
def execute(self, app): name = self['name'] if not name or name == 'default': name = 'Function' # Initialize blocks that will contain our gCode blocks = [] block = Block(name) #Variable definitions formula = self['form'] res = self['res'] # X resolution ran = [self['ranX'], self['ranY']] # Range of X,Y, from -10, to 10 range is 20 cent = [self['centX'], self['centY']] # Coordinates X,Y of the center from bottom left of the coordinate system dim = [self['dimX'], self['dimY']] # Real dimensions in gcode units spacX = self['spacX'] # Spacing of X axis lines spacY = self['spacY'] # Spacing of Y axis lines lin = self['lin'] # Small value - length of a line in gcode units draw = self['draw'] # Draw the coordinate system block.append("(Generated with a script by kswiorek)\n") block.append("(Equation: " + formula +")\n") block.append("(Resolution: " + str(res) +")\n") block.append("(Range: " + str(ran) +")\n") block.append("(Center: " + str(cent) +")\n") block.append("(Dimensions: " + str(dim) +")\n") block.append("(SpacingXY: " + str(spacX) +", " + str(spacY) +")\n") def mapc(var, axis): #Map coordinate systems return (var * (dim[axis]/ran[axis])) #Define coordinate system mins and maxes minX = -cent[0] maxX = ran[0]-cent[0] minY = -cent[1] maxY = ran[1]-cent[1] #Define domain and codomain X = [] Y = [] e_old = "" #Store old exception to comapre #Calculate values for arguments with a resolution for i in range(0, int(ran[0]/res+1)): #Complaints about values beeing floats x = i*res + minX #Iterate x X.append(x) try: Y.append(eval(formula)) except Exception as exc: #Append None, not to loose sync with X Y.append(None) e = str(exc) if e != e_old: #If there is a different exception - display it print("Warning: " + str(e)) app.setStatus(_("Warning: " + str(e))) e_old = e raised = True # Z axis is raised at start #Clip values out of bounds, replace with None, not to loose sync with X for i, item in enumerate(Y): y = Y[i] if not y is None and (y < minY or y > maxY): Y[i] = None #Y without "None", min() and max() can't compare them Ynn = [] #Y no Nones for i, item in enumerate(Y): if not Y[i] is None: Ynn.append(Y[i]) block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])])) #Set feedrate if draw: #If the user selected to draw the coordinate system #X axis block.append(CNC.grapid(z=3)) block.append(CNC.grapid(0, mapc(cent[1], 1))) #1st point of X axis line block.append(CNC.grapid(z=0)) block.append(CNC.gline(dim[0] + lin*1.2, mapc(cent[1], 1))) #End of X axis line + a bit more for the arrow block.append(CNC.gline(dim[0] - lin/2, mapc(cent[1], 1) - lin / 2)) #bottom part of the arrow block.append(CNC.grapid(z=3)) block.append(CNC.grapid(dim[0] + lin*1.2, mapc(cent[1], 1), 0)) #End of X axis line block.append(CNC.grapid(z=0)) block.append(CNC.gline(dim[0] - lin/2, mapc(cent[1], 1) + lin / 2)) #top part of the arrow block.append(CNC.grapid(z=3)) #Y axis, just inverted x with y block.append(CNC.grapid(z=3)) block.append(CNC.grapid(mapc(cent[0], 0), 0)) #1st point of Y axis line block.append(CNC.grapid(z=0)) block.append(CNC.gline(mapc(cent[0], 0), dim[1] + lin*1.2)) #End of Y axis line + a bit more for the arrow block.append(CNC.gline(mapc(cent[0], 0) - lin / 2, dim[1] - lin/2)) #left part of the arrow block.append(CNC.grapid(z=3)) block.append(CNC.grapid(mapc(cent[0], 0), dim[1] + lin*1.2)) #End of Y axis line block.append(CNC.grapid(z=0)) block.append(CNC.gline(mapc(cent[0], 0) + lin / 2, dim[1] - lin/2)) #right part of the arrow block.append(CNC.grapid(z=3)) #X axis number lines i = 0 while i < ran[0] - cent[0]: #While i is on the left of the arrow i +=spacX #Add line spacing #Draw lines right of the center block.append(CNC.grapid(mapc(i+cent[0],0), mapc(cent[1], 1) + lin/2)) block.append(CNC.grapid(z=0)) block.append(CNC.gline(mapc(i+cent[0],0), mapc(cent[1], 1) - lin/2)) block.append(CNC.grapid(z=3)) i = 0 while i > -cent[0]: #While i is lower than center coordinate, inverted for easier math i -=spacX #Add line spacing #Draw lines left of the center block.append(CNC.grapid(mapc(i+cent[0],0), mapc(cent[1], 1) + lin/2)) block.append(CNC.grapid(z=0)) block.append(CNC.gline(mapc(i+cent[0],0), mapc(cent[1], 1) - lin/2)) block.append(CNC.grapid(z=3)) #Y axis number lines i = 0 while i < ran[1] - cent[1]: #While i is between the center and the arrow i +=spacX #Add line spacing #Draw lines top of the center (everything just inverted) block.append(CNC.grapid(mapc(cent[0], 0) + lin/2, mapc(i+cent[1],1))) block.append(CNC.grapid(z=0)) block.append(CNC.gline(mapc(cent[0], 0) - lin/2, mapc(i+cent[1],1))) block.append(CNC.grapid(z=3)) i = 0 while i > -1*cent[1]: i -=spacX #Add line spacing #Draw lines bottom of the center block.append(CNC.grapid(mapc(cent[0], 0) + lin/2, mapc(i+cent[1],1))) block.append(CNC.grapid(z=0)) block.append(CNC.gline(mapc(cent[0], 0) - lin/2, mapc(i+cent[1],1))) block.append(CNC.grapid(z=3)) raised = True #Z was raised #Draw graph for i, item in enumerate(Y): if not Y[i] is None: x = mapc(X[i]+cent[0], 0) #Take an argument y = mapc(Y[i]+cent[1], 1) #Take a value else: y = Y[i] #only for tne None checks next if y is None and not raised: #If a None "period" just started raise Z raised = True block.append(CNC.grapid(z=3)) elif not y is None and raised: #If Z was raised and the None "period" ended move to new coordinates block.append(CNC.grapid(round(x, 2),round(y, 2))) block.append(CNC.grapid(z=0)) #Lower Z raised = False elif not y is None and not raised: #Nothing to do with Nones? Just draw block.append(CNC.gline(round(x, 2),round(y, 2))) block.append(CNC.grapid(z=3)) #Raise on the end blocks.append(block) active = app.activeBlock() app.gcode.insBlocks(active, blocks, 'Function inserted') #insert blocks over active block in the editor app.refresh() #refresh editor app.setStatus(_('Generated function graph')) #feed back result print()
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))
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?"))
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?"))
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)
def appendCircle(block): block.append("m5") block.append(CNC.grapid(x=x0, y=y0 + marksizehalf / 2, f=movefeed)) block.append(self.getPowerLine(app)) block.append(CNC.garc(2, x=x0, y=y0 + marksizehalf / 2, j=-marksizehalf / 2, i=0, f=drawfeed)) block.append("m5")
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))
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)))
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
def execute(self, app): name = self['name'] if not name or name == 'default': name = 'Function' # Initialize blocks that will contain our gCode blocks = [] block = Block(name) #Variable definitions formula = self['form'] res = self['res'] # X resolution ran = [self['ranX'], self['ranY']] # Range of X,Y, from -10, to 10 range is 20 cent = [ self['centX'], self['centY'] ] # Coordinates X,Y of the center from bottom left of the coordinate system dim = [self['dimX'], self['dimY']] # Real dimensions in gcode units spacX = self['spacX'] # Spacing of X axis lines spacY = self['spacY'] # Spacing of Y axis lines lin = self['lin'] # Small value - length of a line in gcode units draw = self['draw'] # Draw the coordinate system block.append("(Generated with a script by kswiorek)\n") block.append("(Equation: " + formula + ")\n") block.append("(Resolution: " + str(res) + ")\n") block.append("(Range: " + str(ran) + ")\n") block.append("(Center: " + str(cent) + ")\n") block.append("(Dimensions: " + str(dim) + ")\n") block.append("(SpacingXY: " + str(spacX) + ", " + str(spacY) + ")\n") def mapc(var, axis): #Map coordinate systems return (var * (dim[axis] / ran[axis])) #Define coordinate system mins and maxes minX = -cent[0] maxX = ran[0] - cent[0] minY = -cent[1] maxY = ran[1] - cent[1] #Define domain and codomain X = [] Y = [] e_old = "" #Store old exception to comapre #Calculate values for arguments with a resolution for i in range(0, int(ran[0] / res + 1)): #Complaints about values beeing floats x = i * res + minX #Iterate x X.append(x) try: Y.append(eval(formula)) except Exception as exc: #Append None, not to loose sync with X Y.append(None) e = str(exc) if e != e_old: #If there is a different exception - display it print("Warning: " + str(e)) app.setStatus(_("Warning: " + str(e))) e_old = e raised = True # Z axis is raised at start #Clip values out of bounds, replace with None, not to loose sync with X for i, item in enumerate(Y): y = Y[i] if not y is None and (y < minY or y > maxY): Y[i] = None #Y without "None", min() and max() can't compare them Ynn = [] #Y no Nones for i, item in enumerate(Y): if not Y[i] is None: Ynn.append(Y[i]) block.append(CNC.gcode(1, [("f", CNC.vars["cutfeed"])])) #Set feedrate if draw: #If the user selected to draw the coordinate system #X axis block.append(CNC.grapid(z=3)) block.append(CNC.grapid(0, mapc(cent[1], 1))) #1st point of X axis line block.append(CNC.grapid(z=0)) block.append(CNC.gline(dim[0] + lin * 1.2, mapc( cent[1], 1))) #End of X axis line + a bit more for the arrow block.append( CNC.gline(dim[0] - lin / 2, mapc(cent[1], 1) - lin / 2)) #bottom part of the arrow block.append(CNC.grapid(z=3)) block.append(CNC.grapid(dim[0] + lin * 1.2, mapc(cent[1], 1), 0)) #End of X axis line block.append(CNC.grapid(z=0)) block.append( CNC.gline(dim[0] - lin / 2, mapc(cent[1], 1) + lin / 2)) #top part of the arrow block.append(CNC.grapid(z=3)) #Y axis, just inverted x with y block.append(CNC.grapid(z=3)) block.append(CNC.grapid(mapc(cent[0], 0), 0)) #1st point of Y axis line block.append(CNC.grapid(z=0)) block.append(CNC.gline( mapc(cent[0], 0), dim[1] + lin * 1.2)) #End of Y axis line + a bit more for the arrow block.append( CNC.gline(mapc(cent[0], 0) - lin / 2, dim[1] - lin / 2)) #left part of the arrow block.append(CNC.grapid(z=3)) block.append(CNC.grapid(mapc(cent[0], 0), dim[1] + lin * 1.2)) #End of Y axis line block.append(CNC.grapid(z=0)) block.append( CNC.gline(mapc(cent[0], 0) + lin / 2, dim[1] - lin / 2)) #right part of the arrow block.append(CNC.grapid(z=3)) #X axis number lines i = 0 while i < ran[0] - cent[0]: #While i is on the left of the arrow i += spacX #Add line spacing #Draw lines right of the center block.append( CNC.grapid(mapc(i + cent[0], 0), mapc(cent[1], 1) + lin / 2)) block.append(CNC.grapid(z=0)) block.append( CNC.gline(mapc(i + cent[0], 0), mapc(cent[1], 1) - lin / 2)) block.append(CNC.grapid(z=3)) i = 0 while i > -cent[ 0]: #While i is lower than center coordinate, inverted for easier math i -= spacX #Add line spacing #Draw lines left of the center block.append( CNC.grapid(mapc(i + cent[0], 0), mapc(cent[1], 1) + lin / 2)) block.append(CNC.grapid(z=0)) block.append( CNC.gline(mapc(i + cent[0], 0), mapc(cent[1], 1) - lin / 2)) block.append(CNC.grapid(z=3)) #Y axis number lines i = 0 while i < ran[1] - cent[ 1]: #While i is between the center and the arrow i += spacX #Add line spacing #Draw lines top of the center (everything just inverted) block.append( CNC.grapid( mapc(cent[0], 0) + lin / 2, mapc(i + cent[1], 1))) block.append(CNC.grapid(z=0)) block.append( CNC.gline( mapc(cent[0], 0) - lin / 2, mapc(i + cent[1], 1))) block.append(CNC.grapid(z=3)) i = 0 while i > -1 * cent[1]: i -= spacX #Add line spacing #Draw lines bottom of the center block.append( CNC.grapid( mapc(cent[0], 0) + lin / 2, mapc(i + cent[1], 1))) block.append(CNC.grapid(z=0)) block.append( CNC.gline( mapc(cent[0], 0) - lin / 2, mapc(i + cent[1], 1))) block.append(CNC.grapid(z=3)) raised = True #Z was raised #Draw graph for i, item in enumerate(Y): if not Y[i] is None: x = mapc(X[i] + cent[0], 0) #Take an argument y = mapc(Y[i] + cent[1], 1) #Take a value else: y = Y[i] #only for tne None checks next if y is None and not raised: #If a None "period" just started raise Z raised = True block.append(CNC.grapid(z=3)) elif not y is None and raised: #If Z was raised and the None "period" ended move to new coordinates block.append(CNC.grapid(round(x, 2), round(y, 2))) block.append(CNC.grapid(z=0)) #Lower Z raised = False elif not y is None and not raised: #Nothing to do with Nones? Just draw block.append(CNC.gline(round(x, 2), round(y, 2))) block.append(CNC.grapid(z=3)) #Raise on the end blocks.append(block) active = app.activeBlock() app.gcode.insBlocks(active, blocks, 'Function inserted' ) #insert blocks over active block in the editor app.refresh() #refresh editor app.setStatus(_('Generated function graph')) #feed back result print()
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"))
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))
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
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
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))
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
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))))
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
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
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))))
def accelerateIfNeeded(self,ztogo,drillfeed): if self.safeZforG0>0: self.block.append(CNC.grapid(z=ztogo+self.safeZforG0)) kwargs={"f":float(drillfeed)} self.block.append(CNC.gline(None,None,ztogo,**kwargs))