Exemple #1
0
 def filter_toolpath(self, toolpath):
     new_path = []
     last_pos = None
     optional_moves = []
     for move_type, args in toolpath:
         if move_type in (MOVE_STRAIGHT, MOVE_STRAIGHT_RAPID):
             if last_pos:
                 # find all remaining pieces of this line
                 inner_lines = []
                 for polygon in self.settings["polygons"]:
                     inner, outer = polygon.split_line(Line(last_pos, args))
                     inner_lines.extend(inner)
                 # turn these lines into moves
                 for line in inner_lines:
                     if pdist(line.p1, last_pos) > epsilon:
                         new_path.append((MOVE_SAFETY, None))
                         new_path.append((move_type, line.p1))
                     else:
                         # we continue were we left
                         if optional_moves:
                             new_path.extend(optional_moves)
                             optional_moves = []
                     new_path.append((move_type, line.p2))
                     last_pos = line.p2
                 optional_moves = []
                 # finish the line by moving to its end (if necessary)
                 if pdist(last_pos, args) > epsilon:
                     optional_moves.append((MOVE_SAFETY, None))
                     optional_moves.append((move_type, args))
             last_pos = args
         elif move_type == MOVE_SAFETY:
             optional_moves = []
         else:
             new_path.append((move_type, args))
     return new_path
Exemple #2
0
 def filter_toolpath(self, toolpath):
     feedrate = min_feedrate = 1
     new_path = []
     last_pos = None
     limit = self.settings["timelimit"]
     duration = 0
     for move_type, args in toolpath:
         if move_type in (MOVE_STRAIGHT, MOVE_STRAIGHT_RAPID):
             if last_pos:
                 new_distance = pdist(args, last_pos)
                 new_duration = new_distance / max(feedrate, min_feedrate)
                 if (new_duration > 0) and (duration + new_duration > limit):
                     partial = (limit - duration) / new_duration
                     destination = padd(last_pos, pmul(psub(args, last_pos), partial))
                     duration = limit
                 else:
                     destination = args
                     duration += new_duration
             else:
                 destination = args
             new_path.append((move_type, destination))
             last_pos = args
         if (move_type == MACHINE_SETTING) and (args[0] == "feedrate"):
             feedrate = args[1]
         if duration >= limit:
             break
     return new_path
Exemple #3
0
 def is_near_list(point_list, point, distance):
     for p in point_list:
         if pdist(p, point) <= distance:
             return True
     return False
Exemple #4
0
        def simplify_polygon_intersections(lines):
            new_group = lines[:]
            # remove all non-adjacent intersecting lines (this splits the group)
            if len(new_group) > 0:
                group_starts = []
                index1 = 0
                while index1 < len(new_group):
                    index2 = 0
                    while index2 < len(new_group):
                        index_distance = min(
                            abs(index2 - index1),
                            abs(len(new_group) - (index2 - index1)))
                        # skip neighbours
                        if index_distance > 1:
                            line1 = new_group[index1]
                            line2 = new_group[index2]
                            intersection, factor = line1.get_intersection(
                                line2)
                            if intersection and (pdist(intersection, line1.p1) > epsilon) \
                                    and (pdist(intersection, line1.p2) > epsilon):
                                del new_group[index1]
                                new_group.insert(index1,
                                                 Line(line1.p1, intersection))
                                new_group.insert(index1 + 1,
                                                 Line(intersection, line1.p2))
                                # Shift all items in "group_starts" by one if
                                # they reference a line whose index changed.
                                for i in range(len(group_starts)):
                                    if group_starts[i] > index1:
                                        group_starts[i] += 1
                                if index1 + 1 not in group_starts:
                                    group_starts.append(index1 + 1)
                                # don't update index2 -> maybe there are other hits
                            elif intersection and (pdist(
                                    intersection, line1.p1) < epsilon):
                                if index1 not in group_starts:
                                    group_starts.append(index1)
                                index2 += 1
                            else:
                                index2 += 1
                        else:
                            index2 += 1
                    index1 += 1
                # The lines intersect each other
                # We need to split the group.
                if len(group_starts) > 0:
                    group_starts.sort()
                    groups = []
                    last_start = 0
                    for group_start in group_starts:
                        transfer_group = new_group[last_start:group_start]
                        # add only non-empty groups
                        if transfer_group:
                            groups.append(transfer_group)
                        last_start = group_start

                    # Add the remaining lines to the first group or as a new
                    # group.
                    if groups[0][0].p1 == new_group[-1].p2:
                        groups[0] = new_group[last_start:] + groups[0]
                    else:
                        groups.append(new_group[last_start:])
                    # try to find open groups that can be combined
                    combined_groups = []
                    for index, current_group in enumerate(groups):
                        # Check if the group is not closed: try to add it to
                        # other non-closed groups.
                        if current_group[0].p1 == current_group[-1].p2:
                            # a closed group
                            combined_groups.append(current_group)
                        else:
                            # the current group is open
                            for other_group in groups[index + 1:]:
                                if other_group[0].p1 != other_group[-1].p2:
                                    # This group is also open - a candidate
                                    # for merging?
                                    if other_group[0].p1 == current_group[
                                            -1].p2:
                                        current_group.reverse()
                                        for line in current_group:
                                            other_group.insert(0, line)
                                        break
                                    if other_group[-1].p2 == current_group[
                                            0].p1:
                                        other_group.extend(current_group)
                                        break
                            else:
                                # not suitable open group found
                                combined_groups.append(current_group)
                    return combined_groups
                else:
                    # just return one group without intersections
                    return [new_group]
            else:
                return None
Exemple #5
0
 def dist_to_point(self, p):
     return pdist(p, self.closest_point(p))
Exemple #6
0
 def get_cost(self, other):
     return pdist(other.start, self.end)
Exemple #7
0
 def test_point_near(p, others):
     for o in others:
         if pdist(p, o) < max_dist:
             return True
     return False
Exemple #8
0
    def get_offset_polygons_validated(self, offset):
        if self.is_outer():
            inside_shifting = max(0, -offset)
        else:
            inside_shifting = max(0, offset)
        if inside_shifting * 2 >= self.get_max_inside_distance():
            # no polygons will be left
            return []
        points = []
        for index in range(len(self._points)):
            points.append(self.get_shifted_vertex(index, offset))
        max_dist = 1000 * epsilon

        def test_point_near(p, others):
            for o in others:
                if pdist(p, o) < max_dist:
                    return True
            return False

        reverse_lines = []
        shifted_lines = []
        for index, p1 in enumerate(points):
            next_index = (index + 1) % len(points)
            p2 = points[next_index]
            diff = psub(p2, p1)
            old_dir = pnormalized(
                psub(self._points[next_index], self._points[index]))
            if pnormalized(diff) != old_dir:
                # the direction turned around
                if pnorm(diff) > max_dist:
                    # the offset was too big
                    return None
                else:
                    reverse_lines.append(index)
                shifted_lines.append((True, Line(p1, p2)))
            else:
                shifted_lines.append((False, Line(p1, p2)))
        # look for reversed lines
        index = 0
        while index < len(shifted_lines):
            line_reverse, line = shifted_lines[index]
            if line_reverse:
                prev_index = (index - 1) % len(shifted_lines)
                next_index = (index + 1) % len(shifted_lines)
                prev_reverse, prev_line = shifted_lines[prev_index]
                while prev_reverse and (prev_index != next_index):
                    prev_index = (prev_index - 1) % len(shifted_lines)
                    prev_reverse, prev_line = shifted_lines[prev_index]
                if prev_index == next_index:
                    # no lines are left
                    print("out 1")
                    return []
                next_reverse, next_line = shifted_lines[next_index]
                while next_reverse and (prev_index != next_index):
                    next_index = (next_index + 1) % len(shifted_lines)
                    next_reverse, next_line = shifted_lines[next_index]
                if prev_index == next_index:
                    # no lines are left
                    print("out 2")
                    return []
                if pdist(prev_line.p2, next_line.p1) > max_dist:
                    cp, dist = prev_line.get_intersection(next_line)
                else:
                    cp = prev_line.p2
                if cp:
                    shifted_lines[prev_index] = (False, Line(prev_line.p1, cp))
                    shifted_lines[next_index] = (False, Line(cp, next_line.p2))
                else:
                    cp, dist = prev_line.get_intersection(next_line,
                                                          infinite_lines=True)
                    raise BaseException(
                        "Expected intersection not found: %s - %s - %s(%d) / %s(%d)"
                        % (cp, shifted_lines[prev_index + 1:next_index],
                           prev_line, prev_index, next_line, next_index))
                if index > next_index:
                    # we wrapped around the end of the list
                    break
                else:
                    index = next_index + 1
            else:
                index += 1
        non_reversed = [
            one_line for rev, one_line in shifted_lines
            if not rev and one_line.len > 0
        ]
        # split the list of lines into groups (based on intersections)
        split_points = []
        index = 0
        while index < len(non_reversed):
            other_index = 0
            while other_index < len(non_reversed):
                other_line = non_reversed[other_index]
                if (other_index == index) \
                        or (other_index == ((index - 1) % len(non_reversed))) \
                        or (other_index == ((index + 1) % len(non_reversed))):
                    # skip neighbours
                    other_index += 1
                    continue
                line = non_reversed[index]
                cp, dist = line.get_intersection(other_line)
                if cp:
                    if not test_point_near(
                            cp,
                        (line.p1, line.p2, other_line.p1, other_line.p2)):
                        # the collision is not close to an end of the line
                        return None
                    elif (cp == line.p1) or (cp == line.p2):
                        # maybe we have been here before
                        if cp not in split_points:
                            split_points.append(cp)
                    elif (pdist(cp, line.p1) < max_dist) or (pdist(
                            cp, line.p2) < max_dist):
                        if pdist(cp, line.p1) < pdist(cp, line.p2):
                            non_reversed[index] = Line(cp, line.p2)
                        else:
                            non_reversed[index] = Line(line.p1, cp)
                        non_reversed.pop(other_index)
                        non_reversed.insert(other_index,
                                            Line(other_line.p1, cp))
                        non_reversed.insert(other_index + 1,
                                            Line(cp, other_line.p2))
                        split_points.append(cp)
                        if other_index < index:
                            index += 1
                        # skip the second part of this line
                        other_index += 1
                    else:
                        # the split of 'other_line' will be handled later
                        pass
                other_index += 1
            index += 1
        groups = [[]]
        current_group = 0
        split_here = False
        for line in non_reversed:
            if line.p1 in split_points:
                split_here = True
            if split_here:
                split_here = False
                # check if any preceding group fits to the point
                for index, group in enumerate(groups):
                    if not group:
                        continue
                    if index == current_group:
                        continue
                    if group[0].p1 == group[-1].p2:
                        # the group is already closed
                        continue
                    if line.p1 == group[-1].p2:
                        current_group = index
                        groups[current_group].append(line)
                        break
                else:
                    current_group = len(groups)
                    groups.append([line])
            else:
                groups[current_group].append(line)
            if line.p2 in split_points:
                split_here = True

        # try to combine open groups
        for index1, group1 in enumerate(groups):
            if not group1:
                continue
            for index2, group2 in enumerate(groups):
                if not group2:
                    continue
                if index2 <= index1:
                    continue
                if (group1[-1].p2 == group2[0].p1) \
                        and (group1[0].p1 == group2[-1].p2):
                    group1.extend(group2)
                    groups[index2] = []
                    break
        result_polygons = []
        print("********** GROUPS **************")
        for a in groups:
            print(a)
        for group in groups:
            if len(group) <= 2:
                continue
            poly = Polygon(self.plane)
            for line in group:
                try:
                    poly.append(line)
                except ValueError:
                    print("NON_REVERSED")
                    for a in non_reversed:
                        print(a)
                    print(groups)
                    print(split_points)
                    print(poly)
                    print(line)
                    raise
            if self.is_closed and ((not poly.is_closed) or
                                   (self.is_outer() != poly.is_outer())):
                continue
            elif (not self.is_closed) and (poly.get_area() != 0):
                continue
            else:
                result_polygons.append(poly)
        return result_polygons
Exemple #9
0
 def get_distance_between_groups(group1, group2):
     forward = pdist(group1[-1].p2, group2[0].p1)
     backward = pdist(group2[-1].p2, group1[0].p1)
     return min(forward, backward)
Exemple #10
0
def get_free_paths_triangles(models, cutter, p1, p2, return_triangles=False):
    if (len(models) == 0) or ((len(models) == 1) and (models[0] is None)):
        return (p1, p2)
    elif len(models) == 1:
        # only one model is left - just continue
        model = models[0]
    else:
        # multiple models were given - process them in layers
        result = get_free_paths_triangles(models[:1], cutter, p1, p2,
                                          return_triangles)
        # group the result into pairs of two points (start/end)
        point_pairs = []
        while result:
            pair1 = result.pop(0)
            pair2 = result.pop(0)
            point_pairs.append((pair1, pair2))
        all_results = []
        for pair in point_pairs:
            one_result = get_free_paths_triangles(models[1:], cutter, pair[0],
                                                  pair[1], return_triangles)
            all_results.extend(one_result)
        return all_results

    backward = pnormalized(psub(p1, p2))
    forward = pnormalized(psub(p2, p1))
    xyz_dist = pdist(p2, p1)

    minx = min(p1[0], p2[0])
    maxx = max(p1[0], p2[0])
    miny = min(p1[1], p2[1])
    maxy = max(p1[1], p2[1])
    minz = min(p1[2], p2[2])

    # find all hits along scan line
    hits = []

    triangles = model.triangles(minx - cutter.distance_radius,
                                miny - cutter.distance_radius, minz,
                                maxx + cutter.distance_radius,
                                maxy + cutter.distance_radius, INFINITE)

    for t in triangles:
        (cl1, d1, cp1) = cutter.intersect(backward, t, start=p1)
        if cl1:
            hits.append(Hit(cl1, cp1, t, -d1, backward))
        (cl2, d2, cp2) = cutter.intersect(forward, t, start=p1)
        if cl2:
            hits.append(Hit(cl2, cp2, t, d2, forward))

    # sort along the scan direction
    hits.sort(key=lambda h: h.d)

    count = 0
    points = []
    for h in hits:
        if h.dir == forward:
            if count == 0:
                if -epsilon <= h.d <= xyz_dist + epsilon:
                    if len(points) == 0:
                        points.append((p1, None, None))
                    points.append((h.cl, h.t, h.cp))
            count += 1
        else:
            if count == 1:
                if -epsilon <= h.d <= xyz_dist + epsilon:
                    points.append((h.cl, h.t, h.cp))
            count -= 1

    if len(points) % 2 == 1:
        points.append((p2, None, None))

    if len(points) == 0:
        # check if the path is completely free or if we are inside of the model
        inside_counter = 0
        for h in hits:
            if -epsilon <= h.d:
                # we reached the outer limit of the model
                break
            if h.dir == forward:
                inside_counter += 1
            else:
                inside_counter -= 1
        if inside_counter <= 0:
            # we are not inside of the model
            points.append((p1, None, None))
            points.append((p2, None, None))

    if return_triangles:
        return points
    else:
        # return only the cutter locations (without triangles)
        return [cut_info[0] for cut_info in points]