def broach(self, _): cfg = self.cfg cfg.ncInit() mill = cfg.mill if abs(self.yEnd - self.yStart) < MIN_DIST: xFeed = True dist = self.xEnd - self.xStart loc = self.xStart elif abs(self.xEnd - self.xStart) < MIN_DIST: xFeed = False dist = self.yEnd - self.yStart loc = self.yStart passes = int(ceil(abs(dist / self.step))) step = abs(dist / passes) dprt("dist %7.4f passes %d step %6.4f" % (dist, passes, step)) if dist < 0: step = -step mill.safeZ() mill.move((self.xStart, self.yStart)) mill.retract() for i in range(passes): loc += step comment = "pass %d/%d" % (i + 1, passes) if xFeed: mill.move((loc, self.yStart), comment=comment) else: mill.move((self.xStart, loc), comment=comment) mill.plungeZ(self.depth) mill.retract() mill.blankLine() mill.safeZ()
def addExit1(self, path): q = self.quadrant (x, y) = path[-1].p1 (xStr, yStr) = path[0].p0 r = self.leadRadius if q == XPLUS: if y > yStr: y += r a0 = 180 a1 = 270 direction = CW ex = 0 else: y -= r a0 = 90 a1 = 180 direction = CCW ex = 1 elif q == YPLUS: if x > xStr: x += r a0 = 180 a1 = 270 direction = CCW ex = 4 else: x -= r a0 = 270 a1 = 360 direction = CW ex = 5 elif q == XMINUS: if y > yStr: y += r a0 = 270 a1 = 360 direction = CCW ex = 2 else: y -= r a0 = 0 a1 = 90 direction = CW ex = 3 elif q == YMINUS: if x > xStr: x += r a0 = 90 a1 = 180 direction = CW ex = 6 else: x -= r a0 = 0 a1 = 90 direction = CCW ex = 7 dprt("exit %d direction %s" % (ex, oStr(self.cfg.dir))) l = Arc((x, y), r, a0, a1, direction=direction) path.append(l)
def addEntry1(self, path): q = self.quadrant (x, y) = path[0].p0 (xEnd, yEnd) = path[-1].p1 r = self.leadRadius if q == XPLUS: if y > yEnd: y += r a0 = 180 a1 = 270 direction = CCW en = 0 else: y -= r a0 = 90 a1 = 180 direction = CW en = 1 elif q == YPLUS: if x > xEnd: x += r a0 = 180 a1 = 270 direction = CW en = 4 else: x -= r a0 = 270 a1 = 360 direction = CCW en = 5 elif q == XMINUS: if y > yEnd: y += r a0 = 270 a1 = 360 direction = CW en = 2 else: y -= r a0 = 0 a1 = 90 direction = CCW en = 3 elif q == YMINUS: if x > xEnd: x += r a0 = 90 a1 = 180 direction = CCW en = 6 else: x -= r a0 = 0 a1 = 90 direction = CW en = 7 dprt("entry %d direction %s" % (en, oStr(self.cfg.dir))) l = Arc((x, y), r, a0, a1, direction=direction) path.insert(0, l)
def setTrim(self): cfg = self.cfg dxf = cfg.dxfInput draw = cfg.draw offset = self.cfg.endMillSize / 2.0 if self.fixture: (xMin, yMin) = (self.xMin, self.yMin) (xMax, yMax) = (self.xMax, self.yMax) else: (xMin, yMin) = (dxf.xMin, dxf.yMin) (xMax, yMax) = (dxf.xMax, dxf.yMax) dprt("xMin %7.4f xMax %7.4f ymin %7.4f yMax %7.4f" % \ (dxf.xMin, dxf.xMax, dxf.yMin, dxf.yMax)) q = self.quadrant trimLayer = "%02d-00-*-trim" % self.layerNum if q == XPLUS_YPLUS: self.xPlus = True self.yPlus = True self.trimX = xMax + offset self.trimY = yMax + offset self.refY = self.minY draw.move((xMin, self.trimY)) draw.line((self.trimX, self.trimY), layer=trimLayer) draw.line((self.trimX, self.refY), layer=trimLayer) elif q == XMINUS_YPLUS: self.xPlus = False self.yPlus = True self.trimX = xMin - offset self.trimY = yMax + offset self.refY = self.minY draw.move((xMax, self.trimY)) draw.line((self.trimX, self.trimY), layer=trimLayer) draw.line((self.trimX, self.refY), layer=trimLayer) elif q == XMINUS_YMINUS: self.xPlus = False self.yPlus = False self.trimX = xMin - offset self.trimY = yMin - offset self.refY = self.maxY draw.move((xMax, self.trimY)) draw.line((self.trimX, self.trimY), layer=trimLayer) draw.line((self.trimX, self.refY), layer=trimLayer) elif q == XPLUS_YMINUS: self.xPlus = True self.yPlus = False self.trimX = xMax + offset self.trimY = yMin - offset self.refY = self.maxY draw.move((xMin, self.trimY)) draw.line((self.trimX, self.trimY), layer=trimLayer) draw.line((self.trimX, self.refY), layer=trimLayer) elif q == XPLUS: pass elif q == YPLUS: pass elif q == XMINUS: pass elif q == YMINUS: pass
def tanTest(self, args): xOffset = 1 yOffset = 1.5 arc = Arc((xOffset, yOffset), 1, 0, 360) # p = (xOffset + 2.598, yOffset + -1.5) # p = (xOffset + 1.5, yOffset + 2.598) p = (xOffset + 2.121, yOffset + 2.121) pt = tangent(p, arc, CCW) dprt("x %7.4f y %7.4f" % (pt[0] - xOffset, pt[1] - yOffset))
def close(self): if self.d is not None: dprt("save drawing file") self.d.save() self.d = None if self.svg is not None: self.svg.add(self.lPath) if self.materialPath is not None: self.svg.add(self.materialPath) self.svg.save() self.svg = None
def __init__(self, cfg): self.cfg = cfg dprt("Rect loaded") self.stepOver = 0.85 self.stepOverPercent = True self.spiral = True self.cmds = \ ( \ ('rectpocket', self.rectPocket, True), \ ('rectstepover', self.setStepOver), \ ('rectspiral', self.setSpiral), \ ('roundedpocket', self.roundedPocket), \ ('rectslot', self.rectSlot,), \ ('openSlot', self.openSlot,), \ # ('', self.), \ )
def drawCross(self, p, layer=None): if layer is None: layer = self.lDebug else: if not layer in self.definedLayers: self.definedLayers[layer] = True self.d.add_layer(layer, color=self.color, lineweight=0) (x, y) = p dprt("cross %2d %7.4f, %7.4f" % (self.lCount, x, y)) labelP(p, "%d" % (self.lCount)) last = self.last self.move((x - 0.02, y)) self.line((x + 0.02, y), layer) self.move((x, y - 0.02)) self.line((x, y + 0.02), layer) self.lCount += 1 self.move(last)
def readFont(self, fontFile): inp = open(fontFile, 'rb') c = ord(' ') while True: minVal = 99 maxVal = -99 val = inp.read(5) if len(val) == 0: break index = int(val.decode()) val = inp.read(3) length = int(val.decode()) l = ord(inp.read(1)) - ord('R') r = ord(inp.read(1)) - ord('R') chArray = [] move = True for i in range(0, length - 1): while True: x = inp.read(1) if ord(x) >= ord(' '): break y = inp.read(1) if ord(x) == ord(' ') and ord(y) == ord('R'): move = True else: x = ord(x) - ord('R') y = ord(y) - ord('R') if y > maxVal: maxVal = y if y < minVal: minVal = y chArray.append([x + abs(l), y, move]) move = False self.letter.append(Letter(r, l, chArray)) val = inp.read(1) if ord(val) != 10: ePrint("error") if self.dbg: dprt("%3d '%1c' length %2d index %4d len %2d l %3d r %3d "\ "max %3d min %3d" % \ (c, c, length, index, len(chArray), l, r, maxVal, minVal)) j = 0 for i, (x, y, move) in enumerate(chArray): dprt("(%2d %3d %3d %5s)" % (i, x, y, move), end=" ") j += 1 if j & 3 == 0: dprt() if j & 3 != 0: dprt() c += 1 if maxVal > self.max: self.max = maxVal if minVal < self.min: self.min = minVal
def modRun(self, args): dprt("modRun") cfg = self.cfg cfg.ncInit() xOffset = 0 yOffset = 0 if True: p0 = (xOffset + (-1), yOffset + 1) p1 = (xOffset + 0, yOffset + 0) p2 = (xOffset + 1, yOffset + 1) else: p0 = (1, 1) p1 = (0, 0) p2 = (1, -1) l0 = Line(p0, p1) l1 = Line(p1, p2) (x, y) = l0.bisect(l1, 1) dprt("%7.4f %7.4f" % (x, y)) dflush()
def lineMid90(self, p0, p1, dbg=False): (x0, y0) = p0 (x1, y1) = p1 xM = (x0 + x1) / 2 yM = (y0 + y1) / 2 dx = x1 - x0 dy = y1 - y0 eqType = abs(dx) > abs(dy) if dbg: dprt("eqType %5s dx %10.6f dy %10.6f" % (eqType, abs(dx), abs(dy))) # eqType = False if eqType: # if dx > dy line y = mx + b per x = -m*y + b m = -dy / dx # negate slope # y = mx + b # b = y - mx b = xM - m * yM # swap positions of x and y else: # if dy > dx x = my + b m = -dx / dy b = yM - m * xM return((not eqType, m, b))
def arcLines(self, mainPath, l, err=0.001, dbg=False): r = l.r adjacent = r - err angle = 2 * degrees(acos(adjacent / r)) a0 = degrees(calcAngle(l.c, l.p0)) a1 = degrees(calcAngle(l.c, l.p1)) if not l.swapped: # clockwise if a1 < a0: a1 += 360.0 if dbg: dprt("a0 %5.1f a1 %5.1f total %5.1f cw" % \ (fix(a0), fix(a1), a1 - a0)) arcAngle = a1 - a0 segments = int(ceil((arcAngle) / angle)) aInc = arcAngle / segments # aRad = radians(aInc) else: # counter clockwise if a0 < a1: a0 += 360.0 if dbg: dprt("a0 %5.1f a1 %5.1f total %5.1f ccw" % \ (fix(a0), fix(a1), a0 - a1)) arcAngle = a0 - a1 segments = int(ceil((arcAngle) / angle)) aInc = -arcAngle / segments if dbg: dprt("segments %d arcAngle %7.2f aInc %7.2f" % \ (segments, arcAngle, aInc)) mainPath.append(intScale(l.p0)) (x, y) = l.c aRad = radians(aInc) a = radians(a0) + aRad for i in range(1, segments): p = (r * cos(a) + x, r * sin(a) + y) if dbg: dprt("%2d a %7.2f (%7.2f %7.2f)" % \ (i, degrees(a), p[0], p[1])) mainPath.append(intScale(p)) a += aRad
def pointsArc(self, p0, p1, p2, dbg=False): if dbg: dprt("p0 (%7.4f %7.4f) p1 (%7.4f %7.4f) "\ "p2 (%7.4f %7.4f) %7.4f %7.4f" % \ (p0[0], p0[1], p1[0], p1[1], p2[0], p2[1], \ xyDist(p0, p1), xyDist(p1, p2))) (eqType0, m0, b0) = self.lineMid90(p0, p1, dbg) (eqType1, m1, b1) = self.lineMid90(p1, p2, dbg) if dbg: dprt("eqType0 %5s m0 %7.4f b0 %7.4f "\ "eqType1 %5s m1 %7.4f b1 %7.4f" % \ (eqType0, m0, b0, eqType1, m1, b1)) if eqType0: if eqType1: # y = m0*x + b0 # y = m1*x + b1 # m0*x + b0 = m1*x + b1 # x*(m0 - m1) = b1 - b0 x = (b1 - b0) / (m0 - m1) y = m0 * x + b0 else: # y = m0*x + b0 # x = m1*y + b1 # y = m0 * (m1*y + b1) + b0 # y = m0*m1*y + m0*b1 + b0 # y - m0*m1*y = m0*b1 + b0 # y * (1 - m0*m1) = m0*b1 + b0 # y = (m0*b1 + b0) / (1 - m0*m1) y = (m0*b1 + b0) / (1 - m0*m1) x = m1 * y + b1 else: if eqType1: x = (m0*b1 + b0) / (1 - m0*m1) y = m1 * x + b1 else: y = (b1 - b0) / (m0 - m1) x = m0 * y + b0 c = (x, y) r0 = xyDist(c, p0) if dbg: r1 = xyDist(c, p1) r2 = xyDist(c, p2) dprt("c (%7.4f %7.4f) r0 %7.4f r1 %7.4f r2 %7.4f" % \ (c[0], c[1], r0, r1, r2)) return((c, r0))
def millHoles(self, _): holes = [] d = Drill(self.mountSize) for p in self.mountInfo: d.addLoc(p) holes.append(d) cfg = self.cfg retract = cfg.retract # save retract value if self.mountRetract is not None: cfg.retract = self.mountRetract else: cfg.retract = cfg.safeZ holeMin = cfg.holeMin holeMax = cfg.holeMax cfg.dxfMillHole(None, holes) cfg.holeMin = holeMin cfg.holeMax = holeMax holes = [] i = 0 for (x, y, size, text) in self.holeInfo: dprt("%2d (%7.4f, %7.4f) size %7.4f %5s" % \ (i, x, y, size, text)) i += 1 size += self.clearance add = True for h in holes: if abs(size - h.size) < MIN_DIST: dprt("add %7.4f to %7.4f" % (size, h.size)) h.addLoc((x, y)) add = False break if add: dprt("new %7.4f" % (size)) d = Drill(size) d.addLoc((x, y)) holes.append(d) if self.retract is not None: cfg.retract = self.retract else: # if retract not specified cfg.retract = retract # restore retract value cfg.dxfMillHole(None, holes) cfg.draw.material(self.xSize, self.ySize)
def makePath(self, points, step, rNum, dbg=False): if False: r = 1 for i in range(4): a0 = float(i) * pi / 2 + pi / 4 a = a0 p0 = (r * cos(a), r * sin(a)) for j in range(2): tmp = (pi, -pi)[j] a = a0 + tmp / 2 p1 = (r * cos(a), r * sin(a)) a = a0 + tmp / 1 p2 = (r * cos(a), r * sin(a)) self.pointsArc(p0, p1, p2) dprt() sys.exit() numPoints = len(points) pLast = points[-1] i = 0 path = [] # points.append(points[0]) o0 = orientation(pLast, points[0], points[1]) if dbg: dprt("path orientation %s" % oStr(o0)) while i < numPoints: p0 = points[i] if dbg: dprt("i %3d (%7.4f %7.4f)" % (i, p0[0], p0[1])) d0 = xyDist(p0, pLast) j = i + 1 pa = p0 while j < numPoints - 1: pj = points[j] dist = xyDist(pa, pj) if abs(dist - d0) > 0.001: if dbg: dprt("dist %9.6f d0 %9.6f" % (dist, d0)) break j += 1 pa = pj delta = j - i if delta < 4: l = Line(pLast, p0, i) txt = "s %d r %d i %d" % (step, rNum, i) l.label(txt) i += 1 pLast = p0 else: p1 = points[i + delta / 2] (c, r) = self.pointsArc(pLast, p1, pa) o = orientation(pLast, p1, pa) if o != o0: (pLast, pa) = (pa, pLast) a0 = degAtan2(pLast[1] - c[1], pLast[0] - c[0]) a1 = degAtan2(pa[1] - c[1], pa[0] - c[0]) l = Arc(c, r, a0, a1, direction=o) if dbg: dprt("arc %s %2d i %d (%7.4f %7.4f) %8.3f "\ " %d (%7.4f %7.4f) %8.3f" % \ (oStr(o), delta, i, pLast[0], pLast[1], a0, \ j, pa[0], pa[1], a1)) i = j pLast = pa if dbg: l.prt() path.append(l) return(path)
def trim(self, path): dprt("trim start %d trimX %7.4f trimy %7.4f xPlus %5s yPlus %5s" % \ (self.layerNum, self.trimX, self.trimY, self.xPlus, self.yPlus)) if self.layerNum == 3: dprt("break") rtnPath = [] for l in path: if l.index == INDEX_MARKER: continue if l.type == ARC: if xyDist((self.trimX, self.trimY), l.c) < l.r: continue # elif l.type == LINE: # rtnPath.append(l) # continue dprt() l.prt() dprt("horz trim") l1 = l.horizontalTrim(self.trimY, self.yPlus) if l1 != None: l1.prt() dprt("vert trim") l1 = l.verticalTrim(self.trimX, self.xPlus) if l1 != None: l1.prt() rtnPath.append(l1) else: dprt("vert returned None") else: dprt("horz returned None") dprt("\ntrim done") return (rtnPath)
def addExit(self, path): l = path[-1] (x, y) = l.p1 dx = x - l.p0[0] dy = y - l.p0[1] r = self.leadRadius if abs(x - self.trimX) < MIN_DIST: if self.xPlus: x += r if dy > 0: a0 = 90 a1 = 180 direction = CW ex = 0 else: a0 = 180 a1 = 270 direction = CCW ex = 1 else: x -= r if dy < 0: a0 = 270 a1 = 360 direction = CW ex = 2 else: a0 = 0 a1 = 90 direction = CCW ex = 3 elif abs(y - self.trimY) < MIN_DIST: if self.yPlus: y += r if dx < 0: a0 = 180 a1 = 270 direction = CW ex = 4 else: a0 = 270 a1 = 360 direction = CCW ex = 5 else: y -= r if dx > 0: a0 = 0 a1 = 90 direction = CW ex = 6 else: a0 = 90 a1 = 180 direction = CCW ex = 7 else: ePrint("error") return dprt("exit %d direction %s" % (ex, oStr(self.cfg.dir))) l = Arc((x, y), r, a0, a1, direction=direction) path.append(l)
def outside(self, args, dbg=True): layer = args[1] cfg = self.cfg # dir = CCW # if cfg.dir is not None and cfg.dir == 'CW': # dir = CW # stepOver = cfg.endMillSize * self.stepOver cfg.ncInit() segments = cfg.dxfInput.getPath(layer) dxf = cfg.dxfInput s = self.symmetry if s == NO_SYMMETRY: pass elif s == UPPER: yMin = (dxf.yMax + dxf.yMin) / 2 p0 = (dxf.xMin, dxf.yMax) p1 = (dxf.xMax, dxf.yMax) p2 = (dxf.xMax, yMin) p3 = (dxf.xMin, yMin) elif s == LOWER: pass elif s == RIGHT: pass elif s == LEFT: pass else: pass p0 = intScale(p0) p1 = intScale(p1) p2 = intScale(p2) p3 = intScale(p3) pco = pyclipper.PyclipperOffset() pc = pyclipper.Pyclipper() clip = (p0, p1, p2, p3) # mp = cfg.getMillPath() self.last = cfg.mill.last for seg in segments: self.pDir = pathDir(seg) mainPath = [] for (i, l) in enumerate(seg): l.draw() if dbg: l.prt() if l.type == LINE: mainPath.append(intScale(l.p0)) elif l.type == ARC: self.arcLines(mainPath, l, dbg=dbg) if dbg: dprt("\nclip") for (i, p) in enumerate(clip): (x, y) = floatScale(p) dprt("%3d (%7.4f %7.4f)" % (i, x, y)) dprt("\nmainPath") for (i, p) in enumerate(mainPath): (x, y) = floatScale(p) dprt("%3d (%7.4f %7.4f)" % (i, x, y)) pco.Clear() pco.AddPath(mainPath, pyclipper.JT_ROUND, False) offset = int((cfg.endMillSize / 2.0) * SCALE) offsetResult = pco.Execute(offset) if dbg: dprt("\noffsetResult len %d" % (len(offsetResult))) for r in offsetResult: dprt("r len %d" % (len(r))) for (i, p) in enumerate(r): (x, y) = floatScale(p) dprt("%3d (%7.4f %7.4f)" % (i, x, y)) dprt() pc.Clear() pc.AddPath(clip, pyclipper.PT_CLIP, True) pc.AddPath(mainPath, pyclipper.PT_SUBJECT, False) result = pc.Execute(pyclipper.CT_INTERSECTION, pyclipper.PFT_EVENODD, pyclipper.PFT_EVENODD) if dbg: for r in result: dprt("\nresult") for (i, p) in enumerate(r): (x, y) = floatScale(p) dprt("%3d (%7.4f %7.4f)" % (i, x, y)) dprt()
def closePath(self, path): q = self.quadrant if q <= XPLUS_YMINUS: if q == XPLUS_YPLUS: p = (self.setMinX(path), self.setMinY(path)) elif q == XMINUS_YPLUS: p = (self.setMaxX(path), self.setMinY(path)) elif q == XMINUS_YMINUS: p = (self.setMaxX(path), self.setMaxY(path)) elif q == XPLUS_YMINUS: p = (self.setMinX(path), self.setMaxY(path)) pStr = path[0].p0 pEnd = path[-1].p1 path.append(Line(pEnd, p, i=INDEX_MARKER)) path.append(Line(p, pStr, i=INDEX_MARKER)) else: path[0].prt() path[-1].prt() (xStr, yStr) = pStr = path[0].p0 (xEnd, yEnd) = pEnd = path[-1].p1 dprt("xStr %7.4f yStr %7.4f xEnd %7.4f yEnd %7.4f" % (xStr, yStr, xEnd, yEnd)) if q == XPLUS: if abs(xStr - xEnd) < MIN_DIST: path.append(Line(pEnd, pStr, i=INDEX_MARKER)) else: if xStr < xEnd: l0Vertical = True p = (xStr, yEnd) else: l0Vertical = False p = (xEnd, yStr) dprt("x %7.4f y %7.4f" % p) l0 = Line(pEnd, p, i=INDEX_MARKER) l1 = Line(p, pStr, i=INDEX_MARKER) if l0Vertical: l0.index -= 1 else: l1.index -= 1 path.append(l0) path.append(l1) elif q == YPLUS: if abs(yStr - yEnd) < MIN_DIST: path.append(Line(pEnd, pStr, i=INDEX_MARKER)) else: if yStr < yEnd: l0Horizontal = True p = (xEnd, yStr) else: l0Horizontal = False p = (xStr, yEnd) dprt("x %7.4f y %7.4f" % p) l0 = Line(pEnd, p, i=INDEX_MARKER) l1 = Line(p, pStr, i=INDEX_MARKER) if l0Horizontal: l0.index -= 1 else: l1.index -= 1 path.append(l0) path.append(l1) elif q == XMINUS: if abs(xStr - xEnd) < MIN_DIST: path.append(Line(pEnd, pStr, i=INDEX_MARKER)) else: if xEnd > xStr: l0Vertical = False p = (xEnd, yStr) else: l0Vertical = True p = (xStr, yEnd) dprt("x %7.4f y %7.4f" % p) l0 = Line(pEnd, p, i=INDEX_MARKER) l1 = Line(p, pStr, i=INDEX_MARKER) if l0Vertical: l0.index -= 1 else: l1.index -= 1 path.append(l0) path.append(l1) pass elif q == YMINUS: if abs(yStr - yEnd) < MIN_DIST: path.append(Line(pEnd, pStr, i=INDEX_MARKER)) else: if yEnd > yStr: l0Horizontal = True p = (xStr, yEnd) else: l0Horizontal = False p = (xEnd, yStr) dprt("x %7.4f y %7.4f" % p) l0 = Line(pEnd, p, i=INDEX_MARKER) l1 = Line(p, pStr, i=INDEX_MARKER) if l0Horizontal: l0.index -= 1 else: l1.index -= 1 path.append(l0) path.append(l1) dprt()
def corner(self, args, dbg=True): cfg = self.cfg # direction = CCW # if cfg.dir is not None and cfg.dir == 'CW': # direction = CW cfg.ncInit() if SIMPLE_BOX: dxf = cfg.dxfInput xMin = dxf.xMin xMax = dxf.xMax yMin = dxf.yMin yMax = dxf.yMax q = self.quadrant if q == XPLUS_YPLUS: xMin = (xMax + xMin) / 2 yMin = (yMax + yMin) / 2 elif q == XMINUS_YPLUS: xMax = (xMax + xMin) / 2 yMin = (yMax + yMin) / 2 elif q == XMINUS_YMINUS: xMax = (xMax + xMin) / 2 yMax = (yMax + yMin) / 2 elif q == XPLUS_YMINUS: xMin = (xMax + xMin) / 2 yMax = (yMax + yMin) / 2 p0 = (xMin, yMax) p1 = (xMax, yMax) p2 = (xMax, yMin) p3 = (xMin, yMin) box = [] box.append(Line(p0, p1)) box.append(Line(p1, p2)) box.append(Line(p2, p3)) box.append(Line(p3, p0)) dprt("\nsimple box") boxLayer = "%02d-00-a-box" % self.layerNum for l in box: l.prt() l.draw(layer=boxLayer) dprt() layer = args[1] segments = cfg.dxfInput.getPath(layer) if len(args) > 2: if args[2] == "break": ePrint("break") # for seg in segments: # for l in seg: # l.prt() # l.draw() # dprt() mp = cfg.getMillPath() for seg in segments: splitSeg = splitArcs(seg) xMax = yMax = MIN_VALUE xMin = yMin = MAX_VALUE for l in splitSeg: l.prt() for (x, y) in (l.p0, l.p1): if x > xMax: # check x xMax = x if x < xMin: xMin = x if y > yMax: # check y yMax = y if y < yMin: yMin = y (self.xMin, self.yMin) = (xMin, yMin) (self.xMax, self.yMax) = (xMax, yMax) dprt("xMin %7.4f xMax %7.4f ymin %7.4f yMax %7.4f" % \ (self.xMin, self.xMax, self.yMin, self.yMax)) dxf = self.cfg.dxfInput dprt("xMin %7.4f xMax %7.4f ymin %7.4f yMax %7.4f" % \ (dxf.xMin, dxf.xMax, dxf.yMin, dxf.yMax)) # for l in splitSeg: # l.draw() if not SIMPLE_BOX: box = self.createBox(splitSeg) if box is None: continue dprt("\ngeneral box") boxLayer = "%02d-00-a-box" % self.layerNum for l in box: l.prt() l.draw(layer=boxLayer) dprt() seg1 = [] for l in splitSeg: (x0, y0) = l.p0 (x1, y1) = l.p1 if l.type == ARC: p = ((x0 + x1) / 2, (y0 + y1) / 2) if (inside(p, box) & 1) == 0: continue elif l.type == LINE: if (inside(l.p0, box) & 1) == 0 and \ (inside(l.p1, box) & 1) == 0: continue seg1.append(l) dprt("seg len %d" % (len(seg1))) if len(seg1) == 0: continue # for l in seg1: # l.prt() # l.draw() dprt("closePath") self.closePath(seg1) closeLayer = "%02d-00-b-close" % self.layerNum for l in seg1: l.prt() l.draw(layer=closeLayer) if self.quadrant <= XPLUS_YMINUS: self.setTrim() offset = cfg.endMillSize / 2.0 + cfg.finishAllowance passes = self.maxPasses # passOffset = self.passOffset if passes == 0: dprt("\nfind max dist") maxD = MIN_VALUE for l in seg1: if l.index <= INDEX_MARKER: continue d = l.pointDistance((self.trimX, self.trimY)) if d is not None: l.prt() dprt("d %7.4f" % (d)) maxD = max(maxD, d) total = maxD - offset passes = int(round(total / self.passOffset)) # passOffset = total / passes dprt("maxD %7.4f total %7.4f passes %d passOffset %7.4f" % \ (maxD, total, passes, self.passOffset)) path = [] for i in range(passes): dprt("\npass %2d offset %7.4f\n" % (i, offset)) seg2 = createPath(seg1, offset, outside=True, keepIndex=True, split=False, dbg=True)[0] pathLayer = "%02d-%02d-c-path" % (self.layerNum, i) for l in seg2: l.draw(layer=pathLayer) if self.quadrant <= XPLUS_YMINUS: dprt() seg3 = self.trim(seg2) trimLayer = "%02d-%02d-d-trim" % (self.layerNum, i) for l in seg3: l.draw(layer=trimLayer) l.label(layer=trimLayer) else: seg3 = [] for l in seg2: if l.index <= INDEX_MARKER: continue seg3.append(l) print("seg3Len %d" % (len(seg3))) if len(seg3) == 0: break path.append(seg3) # dprt() # for l in seg3: # l.prt() # l.draw() offset += self.passOffset cfg.mill.write("(corner %s)\n" % \ (self.quadrantValues[self.quadrant][0])) if self.alternate: finalPath = [] lastPoint = None for (i, seg) in enumerate(path): if (i & 1) != 0: seg = reverseSeg(seg) if lastPoint is not None: finalPath.append(Line(lastPoint, seg[0].p0)) finalPath += seg lastPoint = finalPath[-1].p1 finalPath = reverseSeg(finalPath, makeCopy=False) if self.quadrant <= XPLUS_YMINUS: self.addEntry(finalPath) self.addExit(finalPath) else: self.addEntry1(finalPath) self.addExit1(finalPath) dprt() finalLayer = "%02d-%02d-e-final" % (self.layerNum, i) for l in finalPath: l.prt() l.draw(layer=finalLayer) mp.millPath(finalPath, closed=False, minDist=False) else: for seg in reversed(path): if self.quadrant <= XPLUS_YMINUS: self.addEntry(seg) self.addExit(seg) else: self.addEntry1(seg) self.addExit1(seg) dprt() finalLayer = "%02d-%02d-e-final" % (self.layerNum, i) for l in seg: l.prt() l.draw(layer=finalLayer) mp.millPath(seg, closed=False, minDist=False) self.layerNum += 1
def rectPocket(self, args): layer = args[1] cfg = self.cfg cfg.ncInit() segments = cfg.dxfInput.getPath(layer) for seg in segments: if len(seg) != 4: ePrint("rectPocket wrong number if sides") continue vert = [] horiz = [] for l in seg: if l.type == LINE: if abs(l.p0[0] - l.p1[0]) < MIN_DIST: vert.append(l) elif abs(l.p0[1] - l.p1[1]) < MIN_DIST: horiz.append(l) else: ePrint("rectPocket line not horizontal or vertical") continue else: ePrint("rectPocket segment not a line") continue if len(vert) != 2 or len(horiz) != 2: ePrint("rectPocket incorrect number of sides") continue hl0 = horiz[0] vl0 = vert[0] w = abs(hl0.p0[0] - hl0.p1[0]) # width h = abs(vl0.p0[1] - vl0.p1[1]) # height x = min(hl0.p0[0], hl0.p1[0]) y = min(vl0.p0[1], vl0.p1[1]) self.drawRect(x, y, w, h) stepOver = self.getStepOver() self.path = [] self.index = 0 prev = None offset = cfg.endMillSize / 2.0 + cfg.finishAllowance if self.spiral: dist = min(h, w) / 2.0 - offset if dist < 0: ePrint("rectPocket rectangle too small for end mill") continue passes = int(ceil(dist / stepOver)) stepOver = dist / passes dprt("x %7.4f y %7.4f w %7.4f h %7.4f" % (x, y, w, h)) dprt("passes %2d stepOver %7.4f dist %7.4f" % \ (passes, stepOver, dist)) x0 = x + offset y0 = y + offset w -= 2.0 * offset h -= 2.0 * offset for i in range(passes + 1): dprt("pass %2d x0 %7.4f y0 %7.4f w %7.4f h %7.4f" % \ (i, x0, y0, w, h)) prev = self.millRect(prev, x0, y0, w, h, cfg.dir) x0 += stepOver y0 += stepOver w -= 2 * stepOver h -= 2 * stepOver self.millPath() else: if min(h, w) < cfg.endMillSize + cfg.finishAllowance * 2.0: ePrint("rectPocket rectangle too small for end mill") continue dist = h - 4 * offset + (1 - self.getStepOver()) passes = int(ceil(dist / stepOver)) stepOver = dist / passes r = cfg.endMillSize / 2.0 s = stepOver / 2.0 d = sqrt(r*r - s*s) dprt("x %7.4f y %7.4f w %7.4f h %7.4f" % (x, y, w, h)) dprt("passes %2d offset %7.4f dist %7.4f stepOver %7.4f" \ "d %7.4f" % \ (passes, offset, dist, stepOver, d)) x0 = x + offset y0 = y + offset w -= 2.0 * offset h -= 2.0 * offset prev = self.millRect(None, x0, y0, w, h, cfg.dir) self.drawRect(x0 + offset, y0 + offset, \ w - 2*offset, h - 2*offset) x0 += offset + d y0 += stepOver w -= (offset + d) * 2 h -= offset * 2 if h > 0 and w > 0: sign = 1 for i in range(passes): dprt("pass %2d x0 %7.4f y0 %7.4f w %7.4f h %7.4f" % \ (i, x0, y0, w, h)) x1 = x0 + w if sign > 0: p0 = (x0, y0) p1 = (x1, y0) else: p0 = (x1, y0) p1 = (x0, y0) sign = - sign if prev is not None: self.addLineSeg(prev, p0) self.addLineSeg(p0, p1) self.drawMill(p0) self.drawMill(p1) prev = p1 y0 += stepOver self.millPath()
def write(self, string): self.out.write(string) self.blank = False if self.cfg.printGCode: dprt(string.rstrip('\n')) dflush()
def pocket(self, args, dbg=None): if dbg is None: dbg = self.dbg layer = args[1] cfg = self.cfg # dir = CCW # if cfg.dir is not None and cfg.dir == 'CW': # dir = CW stepOver = cfg.endMillSize * self.stepOver cfg.ncInit() segments = cfg.dxfInput.getPath(layer) pco = PyclipperOffset() mp = cfg.getMillPath() self.last = cfg.mill.last for seg in segments: self.pDir = pathDir(seg) pco.Clear() mainPath = [] for (i, l) in enumerate(seg): l.draw() if dbg: l.prt() if l.type == LINE: mainPath.append(intScale(l.p0)) elif l.type == ARC: self.arcLines(mainPath, l, dbg=dbg) if dbg: dprt() for (i, p) in enumerate(mainPath): (x, y) = floatScale(p) dprt("%3d (%7.4f %7.4f)" % (i, x, y)) dprt() pco.AddPath(mainPath, pyclipper.JT_ROUND, \ pyclipper.ET_CLOSEDPOLYGON) offset = cfg.endMillSize / 2.0 + cfg.finishAllowance step = 0 offsetPaths = [] while True: result = pco.Execute(-int(offset * SCALE)) if dbg: dprt("%2d offset %7.4f results %d" % \ (step, offset, len(result))) if len(result) == 0: break rData = [] for (rNum, r) in enumerate(result): # convert from list of points to lines if self.arcs: pLast = floatScale(r[-1]) index = 0 maxDist = -1 for (i, p) in enumerate(r): p = floatScale(p) dist = xyDist(p, pLast) if dbg: dprt("%3d (%7.4f %7.4f) dist %9.6f" % \ (i, p[0], p[1], dist)) if dist > maxDist: maxDist = dist index = i r[i] = p pLast = p r = r[index:] + r[:index] if dbg: dprt("index %d maxDist %7.4f" % (index, maxDist)) pLast = r[-1] dprt("pLast (%7.4f %7.4f)" % (pLast[0], pLast[1])) for (i, p) in enumerate(r): dprt("%3d (%7.4f %7.4f) dist %9.6f" % \ (i, p[0], p[1], xyDist(p, pLast))) pLast = p dprt() path = self.makePath(r, step, rNum, dbg) else: pLast = floatScale(r[-1]) path = [] for (i, p) in enumerate(r): p = floatScale(p) if dbg: dprt("%3d (%7.4f %7.4f)" % (i, p[0], p[1])) l = Line(pLast, p, i) txt = "s %d r %d i %d" % (step, rNum, i) l.label(txt) path.append(l) pLast = p result[rNum] = path if dbg: dprt() for l in path: l.prt() dprt() # find shortest distance to each path oData = [] for (oNum, oPath) in enumerate(offsetPaths): lEnd = oPath[-1] pEnd = lEnd.p1 minDist = MAX_VALUE index = None for (i, l) in enumerate(path): dist = xyDist(pEnd, l.p0) if dist < minDist: minDist = dist index = i oData.append((index, minDist)) rData.append(oData) # connect to nearest path if dbg and len(result) > 1: dprt("multiple results") oConnect = [False] * len(offsetPaths) while True: minDist = MAX_VALUE index = None rPath = None for (rNum, oData) in enumerate(rData): if oData == None: continue rPath = rNum for (oNum, (i, dist)) in enumerate(oData): if dbg: dprt("step %d rNum %d Onum %d index %3d "\ "dist %9.6f" % \ (step, rNum, oNum, i, dist)) if not oConnect[oNum] and dist < minDist: minDist = dist index = i rIndex = rNum oIndex = oNum if rPath is None: break if index is not None: # connect path if dbg: dprt("connect rIndex %d index %3d to "\ "oIndex %d dist %9.6f" % \ (rIndex, index, oIndex, minDist)) path = result[rIndex] rData[rIndex] = None oConnect[oIndex] = True oPath = offsetPaths[oIndex] oPath.append(Line(oPath[-1].p1, path[index].p0)) oPath += path[index:] + path[:index] else: # add new path if dbg: dprt("add rPath %d oNum %d" % \ (rPath, len(offsetPaths))) rData[rPath] = None path = result[rPath] path = self.closest(path) offsetPaths.append(path) offset += stepOver step += 1 if step > 99: break for path in offsetPaths: mp.millPath(path, closed=False, minDist=False)
def pocket(self, args): layer = args[1] cfg = self.cfg direction = CCW if cfg.dir is not None and cfg.dir == 'CW': direction = CW cfg.ncInit() endAngle = self.endAngle # swapped = False holes = cfg.dxfInput.getHoles(layer) for hole in holes: diameter = hole.size stepOver = self.stepOver * cfg.endMillSize radius = diameter / 2.0 - cfg.finishAllowance - \ cfg.endMillSize / 2.0 if self.spiral: rDist = diameter / 2.0 - cfg.finishAllowance - cfg.endMillSize passes = int(ceil(rDist / stepOver)) stepOver = rDist / passes dprt("diameter %7.4f stepOver %7.4f rDist %7.4f passes %d " \ "radius %7.4f" % \ (diameter, stepOver, rDist, passes, radius)) strAngle = self.strAngle for (x, y) in hole.loc: dprt("center %7.4f %7.4f" % (x, y)) draw = cfg.draw if draw is not None: draw.circle((x, y), diameter / 2) self.path = [] self.index = 0 r = radius self.addSeg(Arc((x, y), r, strAngle, endAngle, \ self.index, direction=direction)) for i in range(passes): rPrev = r a = radians(endAngle) p0 = (rPrev * cos(a) + x, rPrev * sin(a) + y) r -= stepOver arc = Arc((x, y), r, 0.0, 360) p1 = tangent(p0, arc, direction) strAngle = degrees(atan2(p0[0] - x, p0[1] - y)) self.addSeg(Line(p0, p1, self.index)) self.addSeg(Arc((x, y), r, strAngle, endAngle, \ self.index, direction=direction)) self.drawMill(p0) self.drawMill(p1) dprt("pass %d rPrev %7.4f (%7.4f, %7.4f) " \ "r %7.4f (%7.4f, %7.4f)" % \ (i, rPrev, p0[0], p0[1], r, p1[0], p0[1])) self.drawMill(self.path[-1].p1) self.millPath() else: dist = diameter - 2 * cfg.finishAllowance - cfg.endMillSize passes = int(ceil(dist / stepOver)) stepOver = dist / passes radius = diameter / 2.0 - cfg.finishAllowance - \ cfg.endMillSize / 2.0 dprt("diameter %7.4f stepOver %7.4f dist %7.4f passes %d " \ "radius %7.4f" % \ (diameter, stepOver, dist, passes, radius)) strAngle = 90.0 endAngle = strAngle + 360 for (x, y) in hole.loc: dprt("center %7.4f %7.4f" % (x, y)) self.path = [] self.index = 0 self.addSeg(Arc((x, y), radius, strAngle, endAngle, \ self.index, direction=direction)) r1 = radius - cfg.endMillSize / 2.0 a = radians(endAngle) p0 = (-radius * cos(a) + x, radius * sin(a) + y) r = radius - stepOver draw = cfg.draw if draw is not None: draw.circle((x, y), diameter / 2) draw.circle((x, y), radius) draw.circle((x, y), r1) draw.circle((x, y), r) sign = -1 for i in range(passes): dprt("pass %2d r %7.4f" % (i, r)) # if i == 0: y1 = r + y x1 = sqrt(r1 * r1 - r * r) + x r -= stepOver p1 = (sign * x1 + x, y1) self.drawMill(p0) self.drawMill(p1) self.addSeg(Line(p0, p1, self.index)) sign = -sign p0 = (sign * x1 + x, y1) self.addSeg(Line(p1, p0, self.index)) if r1 - abs(r) < MIN_DIST: break self.drawMill(p0) self.millPath()
def scribeLine(self, line): cfg = self.cfg cfg.ncInit() p0 = line.linePoint(self.offset) p1 = line.linePoint(line.length - self.offset) line = Line(p0, p1) segments = int(ceil(line.length / self.probeDist)) segLen = line.length / segments segments += 1 if cfg.level: inp = cfg.probeOpen() if inp is None: return l = inp.readline().strip() l = l.split() zRef = float(l[2]) dprt("zRef %7.4f\n" % (zRef)) levelData = [] for prbData in inp: prbData.strip() (x, y, z) = prbData.split()[:3] x = float(x) y = float(y) z = float(z) dprt("x %7.4f y %7.4f z %7.4f zOffset %7.4f" % \ (x, y, z, z - zRef)) levelData.append((x, y, z - zRef)) levelIndex = 0 inp.close() dprt() else: if cfg.probe: prb = cfg.probeInit() prb.safeZ() prb.move(line.p0) prb.retract() prb.probe(line.p0, comment="reference probe") m = cfg.mill m.safeZ() m.move(line.p0) m.retract() if cfg.level: m.probeSetZ() m.zDepth() zOffset = 0.0 for i in range(segments): dist = i * segLen (x0, y0) = line.linePoint(dist) if cfg.level: zOffset = 0.0 if i < len(levelData): (prbX, prbY, zOffset) = levelData[i] dist = hypot(x0 - prbX, y0 - prbY) dprt("levelIndex %2d x0 %7.4f prbX %7.4f y0 %7.4f "\ "prbY %7.4f dist %7.4f" % \ (levelIndex, x0, prbX, y0, prbY, dist)) if dist < MIN_DIST: levelIndex += 1 else: for levelIndex, (prbX, prbY, zOffset) \ in enumerate(levelData): dist = hypot(x0 - prbX, y0 - prbY) if dist < MIN_DIST: levelIndex += 1 break dprt("x %7.4f y %7.4f zOffset %7.4f" % \ (x0, y0, zOffset)) else: if cfg.probe: prb.probe((x0, y0), comment="point %d" % i) m.cut((x0, y0), zOffset, "zOffset %7.4f" % zOffset)
def addEntry(self, path): l = path[0] (x, y) = l.p0 dx = x - l.p1[0] dy = y - l.p1[1] r = self.leadRadius if abs(x - self.trimX) < MIN_DIST: if self.xPlus: x += r if dy > 0: a0 = 90 a1 = 180 direction = CCW en = 0 else: a0 = 180 a1 = 270 direction = CW en = 1 else: x -= r if dy < 0: a0 = 270 a1 = 360 direction = CCW en = 2 else: a0 = 0 a1 = 90 direction = CW en = 3 elif abs(y - self.trimY) < MIN_DIST: if self.yPlus: y += r if dx < 0: a0 = 180 a1 = 270 direction = CCW en = 4 else: a0 = 270 a1 = 360 direction = CW en = 5 else: y -= r if dx > 0: a0 = 0 a1 = 90 direction = CCW en = 6 else: a0 = 90 a1 = 180 direction = CW en = 7 else: ePrint("addEntry error x %7.4f xTrim %7.4f y %7.4f yTrim %7.4f" % \ (x, self.trimX, y, self.trimY)) return dprt("entry %d direction %s" % (en, oStr(self.cfg.dir))) l = Arc((x, y), r, a0, a1, direction=direction) path.insert(0, l)