'Checks for imperial/relativeness settings and tool changes'

def _preprocess(self, lines=None, build_layers=False, layer_callback=None):

    if (not lines):
        lines = self.lines
    imperial = self.imperial
    relative = self.relative
    relative_e = self.relative_e
    current_tool = self.current_tool
    current_x = self.current_x
    current_y = self.current_y
    current_z = self.current_z
    offset_x = self.offset_x
    offset_y = self.offset_y
    offset_z = self.offset_z
    current_e = self.current_e
    offset_e = self.offset_e
    total_e = self.total_e
    max_e = self.max_e
    current_e_multi = self.current_e_multi[current_tool]
    offset_e_multi = self.offset_e_multi[current_tool]
    total_e_multi = self.total_e_multi[current_tool]
    max_e_multi = self.max_e_multi[current_tool]
    cur_layer_has_extrusion = False
    if build_layers:
        xmin = float('inf')
        ymin = float('inf')
        zmin = 0
        xmax = float('-inf')
        ymax = float('-inf')
        zmax = float('-inf')
        xmin_e = float('inf')
        ymin_e = float('inf')
        xmax_e = float('-inf')
        ymax_e = float('-inf')
        lastx = lasty = lastz = laste = lastf = 0.0
        lastdx = 0
        lastdy = 0
        x = y = e = f = 0.0
        currenttravel = 0.0
        moveduration = 0.0
        totalduration = 0.0
        acceleration = 2000.0
        layerbeginduration = 0.0
        all_layers = self.all_layers = []
        all_zs = self.all_zs = set()
        layer_idxs = self.layer_idxs = []
        line_idxs = self.line_idxs = []
        layer_id = 0
        layer_line = 0
        last_layer_z = None
        prev_z = None
        prev_base_z = (None, None)
        cur_z = None
        cur_lines = []
    if (self.line_class != Line):
        get_line = (lambda l: Line(l.raw))
    else:
        get_line = (lambda l: l)
    for true_line in lines:
        line = get_line(true_line)
        split_raw = split(line)
        if line.command:
            if line.is_move:
                line.relative = relative
                line.relative_e = relative_e
                line.current_tool = current_tool
            elif (line.command == 'G20'):
                imperial = True
            elif (line.command == 'G21'):
                imperial = False
            elif (line.command == 'G90'):
                relative = False
                relative_e = False
            elif (line.command == 'G91'):
                relative = True
                relative_e = True
            elif (line.command == 'M82'):
                relative_e = False
            elif (line.command == 'M83'):
                relative_e = True
            elif (line.command[0] == 'T'):
                current_tool = int(line.command[1:])
                while ((current_tool + 1) > len(self.current_e_multi)):
                    self.current_e_multi += [0]
                    self.offset_e_multi += [0]
                    self.total_e_multi += [0]
                    self.max_e_multi += [0]
            current_e_multi = self.current_e_multi[current_tool]
            offset_e_multi = self.offset_e_multi[current_tool]
            total_e_multi = self.total_e_multi[current_tool]
            max_e_multi = self.max_e_multi[current_tool]
            if (line.command[0] == 'G'):
                parse_coordinates(line, split_raw, imperial)
            if line.is_move:
                x = line.x
                y = line.y
                z = line.z
                if (line.f is not None):
                    self.current_f = line.f
                if line.relative:
                    x = (current_x + (x or 0))
                    y = (current_y + (y or 0))
                    z = (current_z + (z or 0))
                else:
                    if (x is not None):
                        x = (x + offset_x)
                    if (y is not None):
                        y = (y + offset_y)
                    if (z is not None):
                        z = (z + offset_z)
                if (x is not None):
                    current_x = x
                if (y is not None):
                    current_y = y
                if (z is not None):
                    current_z = z
            elif (line.command == 'G28'):
                home_all = (not any([line.x, line.y, line.z]))
                if (home_all or (line.x is not None)):
                    offset_x = 0
                    current_x = self.home_x
                if (home_all or (line.y is not None)):
                    offset_y = 0
                    current_y = self.home_y
                if (home_all or (line.z is not None)):
                    offset_z = 0
                    current_z = self.home_z
            elif (line.command == 'G92'):
                if (line.x is not None):
                    offset_x = (current_x - line.x)
                if (line.y is not None):
                    offset_y = (current_y - line.y)
                if (line.z is not None):
                    offset_z = (current_z - line.z)
            line.current_x = current_x
            line.current_y = current_y
            line.current_z = current_z
            if (line.e is not None):
                if line.is_move:
                    if line.relative_e:
                        line.extruding = (line.e > 0)
                        total_e += line.e
                        current_e += line.e
                        total_e_multi += line.e
                        current_e_multi += line.e
                    else:
                        new_e = (line.e + offset_e)
                        line.extruding = (new_e > current_e)
                        total_e += (new_e - current_e)
                        current_e = new_e
                        new_e_multi = (line.e + offset_e_multi)
                        total_e_multi += (new_e_multi - current_e_multi)
                        current_e_multi = new_e_multi
                    max_e = max(max_e, total_e)
                    max_e_multi = max(max_e_multi, total_e_multi)
                    cur_layer_has_extrusion |= line.extruding
                elif (line.command == 'G92'):
                    offset_e = (current_e - line.e)
                    offset_e_multi = (current_e_multi - line.e)
            self.current_e_multi[current_tool] = current_e_multi
            self.offset_e_multi[current_tool] = offset_e_multi
            self.max_e_multi[current_tool] = max_e_multi
            self.total_e_multi[current_tool] = total_e_multi
            if build_layers:
                if line.is_move:
                    if line.extruding:
                        if (line.current_x is not None):
                            xmin_e = min(xmin_e, line.current_x)
                            xmax_e = max(xmax_e, line.current_x)
                        if (line.current_y is not None):
                            ymin_e = min(ymin_e, line.current_y)
                            ymax_e = max(ymax_e, line.current_y)
                    if (max_e <= 0):
                        if (line.current_x is not None):
                            xmin = min(xmin, line.current_x)
                            xmax = max(xmax, line.current_x)
                        if (line.current_y is not None):
                            ymin = min(ymin, line.current_y)
                            ymax = max(ymax, line.current_y)
                if ((line.command == 'G0') or (line.command == 'G1')):
                    x = (line.x if (line.x is not None) else lastx)
                    y = (line.y if (line.y is not None) else lasty)
                    z = (line.z if (line.z is not None) else lastz)
                    e = (line.e if (line.e is not None) else laste)
                    f = ((line.f / 60.0) if (line.f is not None) else lastf)
                    dx = (x - lastx)
                    dy = (y - lasty)
                    if (((dx * lastdx) + (dy * lastdy)) <= 0):
                        lastf = 0
                    currenttravel = math.hypot(dx, dy)
                    if (currenttravel == 0):
                        if (line.z is not None):
                            currenttravel = (abs(line.z) if line.relative else abs((line.z - lastz)))
                        elif (line.e is not None):
                            currenttravel = (abs(line.e) if line.relative_e else abs((line.e - laste)))
                    if (f == lastf):
                        moveduration = ((currenttravel / f) if (f != 0) else 0.0)
                    else:
                        distance = (2 * abs(((((lastf + f) * (f - lastf)) * 0.5) / acceleration)))
                        if ((distance <= currenttravel) and ((lastf + f) != 0) and (f != 0)):
                            moveduration = ((2 * distance) / (lastf + f))
                            moveduration += ((currenttravel - distance) / f)
                        else:
                            moveduration = ((2 * currenttravel) / (lastf + f))
                    lastdx = dx
                    lastdy = dy
                    totalduration += moveduration
                    lastx = x
                    lasty = y
                    lastz = z
                    laste = e
                    lastf = f
                elif (line.command == 'G4'):
                    moveduration = P(line)
                    if moveduration:
                        moveduration /= 1000.0
                        totalduration += moveduration
                if (line.z is not None):
                    if (line.command == 'G92'):
                        cur_z = line.z
                    elif line.is_move:
                        if (line.relative and (cur_z is not None)):
                            cur_z += line.z
                        else:
                            cur_z = line.z
                if (cur_z != prev_z):
                    if ((prev_z is not None) and (last_layer_z is not None)):
                        offset = (self.est_layer_height if self.est_layer_height else 0.01)
                        if (abs((prev_z - last_layer_z)) < offset):
                            if (self.est_layer_height is None):
                                zs = sorted([l.z for l in all_layers if (l.z is not None)])
                                heights = [round((zs[(i + 1)] - zs[i]), 3) for i in range((len(zs) - 1))]
                                heights = [height for height in heights if height]
                                if (len(heights) >= 2):
                                    self.est_layer_height = heights[1]
                                elif heights:
                                    self.est_layer_height = heights[0]
                                else:
                                    self.est_layer_height = 0.1
                            base_z = round((prev_z - (prev_z % self.est_layer_height)), 2)
                        else:
                            base_z = round(prev_z, 2)
                    else:
                        base_z = prev_z
                    if (base_z != prev_base_z):
                        new_layer = Layer(cur_lines, base_z)
                        new_layer.duration = (totalduration - layerbeginduration)
                        layerbeginduration = totalduration
                        all_layers.append(new_layer)
                        if (cur_layer_has_extrusion and (prev_z not in all_zs)):
                            all_zs.add(prev_z)
                        cur_lines = []
                        cur_layer_has_extrusion = False
                        layer_id += 1
                        layer_line = 0
                        last_layer_z = base_z
                        if (layer_callback is not None):
                            layer_callback(self, (len(all_layers) - 1))
                    prev_base_z = base_z
        if build_layers:
            cur_lines.append(true_line)
            layer_idxs.append(layer_id)
            line_idxs.append(layer_line)
            layer_line += 1
            prev_z = cur_z
    self.imperial = imperial
    self.relative = relative
    self.relative_e = relative_e
    self.current_tool = current_tool
    self.current_x = current_x
    self.current_y = current_y
    self.current_z = current_z
    self.offset_x = offset_x
    self.offset_y = offset_y
    self.offset_z = offset_z
    self.current_e = current_e
    self.offset_e = offset_e
    self.max_e = max_e
    self.total_e = total_e
    self.current_e_multi[current_tool] = current_e_multi
    self.offset_e_multi[current_tool] = offset_e_multi
    self.max_e_multi[current_tool] = max_e_multi
    self.total_e_multi[current_tool] = total_e_multi
    if build_layers:
        if cur_lines:
            new_layer = Layer(cur_lines, prev_z)
            new_layer.duration = (totalduration - layerbeginduration)
            layerbeginduration = totalduration
            all_layers.append(new_layer)
            if (cur_layer_has_extrusion and (prev_z not in all_zs)):
                all_zs.add(prev_z)
        self.append_layer_id = len(all_layers)
        self.append_layer = Layer([])
        self.append_layer.duration = 0
        all_layers.append(self.append_layer)
        self.layer_idxs = array('I', layer_idxs)
        self.line_idxs = array('I', line_idxs)
        all_zs = self.all_zs.union(set([zmin])).difference(set([None]))
        zmin = min(all_zs)
        zmax = max(all_zs)
        self.filament_length = self.max_e
        while (len(self.filament_length_multi) < len(self.max_e_multi)):
            self.filament_length_multi += [0]
        for i in enumerate(self.max_e_multi):
            self.filament_length_multi[i[0]] = i[1]
        if (self.filament_length > 0):
            self.xmin = (xmin_e if (not math.isinf(xmin_e)) else 0)
            self.xmax = (xmax_e if (not math.isinf(xmax_e)) else 0)
            self.ymin = (ymin_e if (not math.isinf(ymin_e)) else 0)
            self.ymax = (ymax_e if (not math.isinf(ymax_e)) else 0)
        else:
            self.xmin = (xmin if (not math.isinf(xmin)) else 0)
            self.xmax = (xmax if (not math.isinf(xmax)) else 0)
            self.ymin = (ymin if (not math.isinf(ymin)) else 0)
            self.ymax = (ymax if (not math.isinf(ymax)) else 0)
        self.zmin = (zmin if (not math.isinf(zmin)) else 0)
        self.zmax = (zmax if (not math.isinf(zmax)) else 0)
        self.width = (self.xmax - self.xmin)
        self.depth = (self.ymax - self.ymin)
        self.height = (self.zmax - self.zmin)
        totaltime = datetime.timedelta(seconds=int(totalduration))
        self.duration = totaltime
