def opcode_filter(self, opcode): if opcode.command == GCODE_RELATIVE_EXTRUSION_COMMAND: self.relative_extrusion = True return if opcode.command == GCODE_ABSOLUTE_EXTRUSION_COMMAND: self.relative_extrusion = False return raw_to_line(GCODE_RELATIVE_EXTRUSION_COMMAND) if opcode.command == GCODE_SET_POSITION_COMMAND: # when setting position, if E is set, use it, but if there is parameter, consider E=0 if opcode.e is not None: self.current_extrusion_distance = Decimal(opcode.e) elif opcode.x is None and opcode.y is None and opcode.z is None: self.current_extrusion_distance = Decimal() return if opcode.command in move_gcodes and not self.relative_extrusion and opcode.e is not None: # we're extruding while in absolute extrusion mode, reduce by the amount extruded so far # and keep track of the current e for later reuse opcode.e, self.current_extrusion_distance = ( opcode.e - float(self.current_extrusion_distance), Decimal(opcode.e)) opcode.relative_e=True unsplit(opcode) return opcode
def to_gcode(self): """ translate a sequence of segments into a circular gcode command :return: the gcode command """ result = [self.queue[0]] last = self.queue.pop() count = len(self.queue) end_point = self.queue[-1] error, circle = self.get_circle() extrusions = self.get_distances() op1 = Line() result.append(op1) op1.command = "G3" if circle.direction > 0 else "G2" # G2 is CW, G3 CCW op1.x = round(circle.end.x, 3) op1.y = round(circle.end.y, 3) op1.i = round(circle.center.x - circle.start.x, 3) op1.j = round(circle.center.y - circle.start.y, 3) if end_point.relative_e: # calculate extrusion correction # arc length b = r·alpha (alpha in radian) # chord length s = 2·r·sin(alpha/2) # resulting arc extrusion is s0*b/s op1.e = sum([ s0 * (circle.radius * alpha) / (2 * circle.radius * sin(alpha / 2)) for s0, alpha in zip(extrusions['filament'].values(), self.get_phase_diffs(circle)) ]) op1.relative_e = True else: # absolute mode: fall-back to the original length phase_diffs = self.get_phase_diffs(circle) arc_lens = [alpha * circle.radius for alpha in phase_diffs] arc_extrusion_length = sum(arc_lens) * extrusions['avg']['ratio'] op1.e = self.queue[0].current_e + arc_extrusion_length op1.relative_e = False rel = arc_extrusion_length / extrusions['total']['filament'] if (rel - 1) > EXTRUSION_CORRECTION_LIMIT: op2 = Line() op2.command = "G92" op2.e = op2.current_e = end_point.current_e unsplit(op2) op2.raw += "; generated as arc to path relation is %f" % rel result.append(op2) op1.f = end_point.current_f unsplit(op1) op1.raw += "; generated from %s segments" % (count - 1) self.valid_circle = False result.append(last) logger.info(" generated arc from %s segments" % (count - 1)) logger.debug("arc is " + str(circle)) return result
def opcode_filter(self, opcode): if opcode.command in move_gcodes: if self.absolute_distance_mode is None: logging.warn( 'Move detected without absolute or related mode selected first' ) return if not self.absolute_distance_mode: # we're in relative mode, if the first move after a homing, translate quickly if self.first_move_after_home: self.first_move_after_home = False return [self.generate_translation(), opcode] return # at this point, we're an absolute move, we have to "hard patch" coordinate if opcode.x is not None and self.translate_x: opcode.x += self.translate_x unsplit(opcode) if opcode.y is not None and self.translate_y: opcode.y += self.translate_y unsplit(opcode) return opcode if opcode.command == GCODE_ABSOLUTE_POSITIONING_COMMAND: self.absolute_distance_mode = True return if opcode.command == GCODE_RELATIVE_POSITIONING_COMMAND: self.absolute_distance_mode = False return if opcode.command == GCODE_SET_POSITION_COMMAND: if opcode.x is None and opcode.y is None and opcode.z is None: # no coordinate given is equivalent to all 0 opcode.x = -self.translate_x opcode.y = -self.translate_y # now, there is a new reference point, that we translated so there's nothing left to do until # the end of the program self.translate_x = self.translate_y = 0 unsplit(opcode) return opcode if opcode.x is not None: opcode.x -= self.translate_x self.translate_x = 0 if opcode.y is not None: opcode.y -= self.translate_y self.translate_y = 0 unsplit(opcode) return opcode
def to_gcode(self): """ translate a sequence of segments into a circular gcode command :return: the gcode command """ result=[self.queue[0]] last = self.queue.pop() count = len(self.queue) end_point = self.queue[-1] error, circle = self.get_circle() extrusions = self.get_distances() op1 = Line() result.append(op1) op1.command = "G3" if circle.direction >0 else "G2" # G2 is CW, G3 CCW op1.x = round(circle.end.x, 3) op1.y = round(circle.end.y, 3) op1.i = round(circle.center.x - circle.start.x, 3) op1.j = round(circle.center.y - circle.start.y, 3) if end_point.relative_e: # calculate extrusion correction # arc length b = r·alpha (alpha in radian) # chord length s = 2·r·sin(alpha/2) # resulting arc extrusion is s0*b/s op1.e = sum([ s0*(circle.radius*alpha)/(2*circle.radius*sin(alpha/2)) for s0, alpha in zip(extrusions['filament'].values(), self.get_phase_diffs(circle))]) op1.relative_e = True else: # absolute mode: fall-back to the original length phase_diffs=self.get_phase_diffs(circle) arc_lens=[ alpha*circle.radius for alpha in phase_diffs] arc_extrusion_length=sum(arc_lens)*extrusions['avg']['ratio'] op1.e=self.queue[0].current_e+arc_extrusion_length op1.relative_e=False rel = arc_extrusion_length/extrusions['total']['filament'] if (rel - 1) > EXTRUSION_CORRECTION_LIMIT: op2= Line() op2.command="G92" op2.e = op2.current_e = end_point.current_e unsplit(op2) op2.raw += "; generated as arc to path relation is %f" % rel result.append(op2) op1.f = end_point.current_f unsplit(op1) op1.raw += "; generated from %s segments" % (count - 1) self.valid_circle = False result.append(last) logger.info(" generated arc from %s segments" % (count - 1)) logger.debug("arc is "+str(circle)) return result
def opcode_filter(self, opcode): if opcode.command in move_gcodes: if self.absolute_distance_mode is None: logging.warn('Move detected without absolute or related mode selected first') return if not self.absolute_distance_mode: # we're in relative mode, if the first move after a homing, translate quickly if self.first_move_after_home: self.first_move_after_home = False return [self.generate_translation(), opcode] return # at this point, we're an absolute move, we have to "hard patch" coordinate if opcode.x is not None and self.translate_x: opcode.x += self.translate_x unsplit(opcode) if opcode.y is not None and self.translate_y: opcode.y += self.translate_y unsplit(opcode) return opcode if opcode.command == GCODE_ABSOLUTE_POSITIONING_COMMAND: self.absolute_distance_mode = True return if opcode.command == GCODE_RELATIVE_POSITIONING_COMMAND: self.absolute_distance_mode = False return if opcode.command == GCODE_SET_POSITION_COMMAND: if opcode.x is None and opcode.y is None and opcode.z is None: # no coordinate given is equivalent to all 0 opcode.x = - self.translate_x opcode.y = - self.translate_y # now, there is a new reference point, that we translated so there's nothing left to do until # the end of the program self.translate_x = self.translate_y = 0 unsplit(opcode) return opcode if opcode.x is not None: opcode.x -= self.translate_x self.translate_x = 0 if opcode.y is not None: opcode.y -= self.translate_y self.translate_y = 0 unsplit(opcode) return opcode
def get_stretched_line_from_index_location(self, indexPreviousStart, indexNextStart, location, original_line): """Get stretched gcode line from line index and location.""" crossIteratorForward = self.line_forward_iterator(indexNextStart, self.current_layer) crossIteratorBackward = self.line_backward_iterator(indexPreviousStart, self.current_layer) iteratorForward = self.line_forward_iterator(indexNextStart, self.current_layer) iteratorBackward = self.line_backward_iterator(indexPreviousStart, self.current_layer) locationComplex = location.dropAxis() logging.debug("original point to stretch: %s", locationComplex) relativeStretch = self.get_relative_stretch(locationComplex, iteratorForward) \ + self.get_relative_stretch(locationComplex, iteratorBackward) relativeStretch *= 0.8 relativeStretch = self.get_cross_limited_stretch(relativeStretch, crossIteratorForward, locationComplex) relativeStretch = self.get_cross_limited_stretch(relativeStretch, crossIteratorBackward, locationComplex) relativeStretchLength = abs(relativeStretch) if relativeStretchLength > 1.0: relativeStretch /= relativeStretchLength logging.debug("relativeStretchLength: %f", relativeStretchLength) absoluteStretch = relativeStretch * self.thread_maximum_absolute_stretch stretchedPoint = location.dropAxis() + absoluteStretch result = Line() result.command = original_line.command result.x = stretchedPoint.real result.y = stretchedPoint.imag result.z = original_line.z result.f = self.feedRateMinute # TODO improve new extrusion length computation. It's clearly a very rough estimate if original_line.e is not None: result.e = original_line.e * (1 - abs(absoluteStretch)) unsplit(result) logging.debug("stretched point: %f %f", result.x, result.y) return result