Beispiel #1
0
 def _compute_toplevel_tour(self):
     """
     find cycle starting at origin and
     passing through one point of each toplevel pocket.
     return list of 2d points.
     this will also sort all children by order of visit of the tour
     and change each cycle starting point as the visited point.
     """
     origin = Point([0, 0])
     graph = Graph()
     children = {}  # record to which child each point belongs
     for child in self.children:
         end = nearest_point(child.old_pocket, origin)
         children[end] = child
         graph.add_edge_between(origin, child.old_pocket,
                                Segment([origin, end]))
     for child1, child2 in combinations(self.children, 2):
         start, end = nearest_points(child1.old_pocket, child2.old_pocket)
         children[start] = child1
         children[end] = child2
         graph.add_edge_between(child1.old_pocket, child2.old_pocket,
                                Segment([start, end]))
     cycle = tsp(graph)
     tour = self._convert_cycle_to_tour(cycle, children, origin)
     return tour
Beispiel #2
0
    def remove_loops(self):
        """
        iterate on edge, remove small loops (un-millable zones).
        """
        left = []
        for segment1, arc, segment2 in self.arcs():
            if arc.reversed_direction:
                i = segment1.intersection_with_segment(segment2)
                if i is None:
                    left.append(arc.endpoints[0])
                    left.append(arc)
                    left.append(arc.endpoints[1])
                else:
                    left.append(i)
            else:
                left.append(arc.endpoints[0])
                left.append(arc)
                left.append(arc.endpoints[1])

        simpler_edge = []
        position = left[-1]
        for part in left:
            if isinstance(part, Arc):
                simpler_edge.append(part)
                position = part.endpoints[1]
            else:
                if position != part:
                    simpler_edge.append(Segment([position, part]))

                position = part
        self.edge = simpler_edge
Beispiel #3
0
    def _odd_segments_on_line(self, line_hash):
        """
        sweeps through line of aligned segments.
        keeping the ones we want
        """
        # associate #starting - #ending segments to each point
        self.counters = defaultdict(int)
        segments = self.lines[line_hash]
        self._compute_points_and_counters(segments)
        # now iterate through each point
        # we record on how many segments we currently are
        previously_on = 0
        # we record where interesting segment started
        previous_point = None

        odd_segments = []

        for point in self.sorted_points:
            now_on = previously_on
            now_on += self.counters[point]
            if previously_on % 2 == 1:
                if now_on % 2 == 0:
                    odd_segments.append(Segment([previous_point, point]))
            else:
                previous_point = point

            previously_on = now_on

        if __debug__:
            if is_module_debugged(__name__):
                tycat(self.segments, odd_segments)
        return odd_segments
Beispiel #4
0
    def join_raw_segments(self, raw_segments):
        """
        reconnect all parallel segments.
        """

        for neighbouring_tuples in all_two_elements(raw_segments):
            first_segment, second_segment = [p[0] for p in neighbouring_tuples]
            end = first_segment.endpoints[1]
            start = second_segment.endpoints[0]
            if end.is_almost(start):
                first_segment = Segment([first_segment.endpoints[0], start])
            else:
                # original point connecting the original segments
                center_point = neighbouring_tuples[0][1].endpoints[1]
                # add arc
                try:
                    binding = Arc(self.radius, [end, start], center_point)
                    binding.adjust_center()
                    binding.correct_endpoints_order()
                except:
                    print("failed joining segments")
                    tycat(self.polygon, center_point, first_segment,
                          second_segment)
                    raise

                self.edge.append(first_segment)
                self.edge.append(binding)

        if __debug__:
            if is_module_debugged(__name__):
                print("joined segments")
                tycat(self.polygon, self.edge)
Beispiel #5
0
    def tycat(self):
        """
        graphical display for debugging
        """
        # compute intersections
        intersections = []
        for small_intersections in self.intersections.values():
            intersections.extend(small_intersections)
        intersections = list(set(intersections))

        # compute current vertical line
        bbox = BoundingBox.empty_box(2)
        for path in self.paths:
            bbox.update(path.get_bounding_box())
        ymin, ymax = bbox.limits(1)
        height = ymax - ymin
        line_y_min = ymin - height / 20
        line_y_max = ymax + height / 20
        current_x = self.current_point.coordinates[0]
        vertical_line = Segment(
            [Point([current_x, line_y_min]),
             Point([current_x, line_y_max])])

        # display figure
        tycat(self.paths, intersections, [self.current_point, vertical_line],
              *self.crossed_paths)

        print(list(self.key(p) for p in self.crossed_paths))
Beispiel #6
0
 def complete_graph(cls, points):
     """
     builds complete graph from set of points.
     """
     graph = cls()
     for points in combinations(points, 2):
         graph.add_edge(Segment(points))
     return graph
Beispiel #7
0
def overlapping_run(size):
    """
    one run, of given size.
    return time taken.
    """
    paths = [
        Segment([Point([0, i]), Point([1, i + 0.5])]) for i in range(size)
    ]
    return run(paths)
Beispiel #8
0
    def _merge_toplevel(self, toplevel_tour):
        """
        tour all points in tour.
        at each point (except first)
        we go down in subtree and back up to continue touring.
        """
        final_paths = []
        for i in range(len(toplevel_tour) - 1):
            start = toplevel_tour[i]
            end = toplevel_tour[i + 1]
            if not start.is_almost(end):
                final_paths.append(Segment([start, end]))
            final_paths.append(VerticalPath(-1))
            final_paths.extend(self.children[i].content.elementary_paths)
            final_paths.append(VerticalPath(1))

        # back to origin
        final_paths.append(Segment([toplevel_tour[-1], toplevel_tour[0]]))
        return Path(final_paths)
Beispiel #9
0
def non_overlapping_run(size):
    """
    one run, of given size.
    return time taken.
    """
    paths = [
        Segment([Point([2 * i, 0]), Point([2 * i + 1, 0])])
        for i in range(size)
    ]
    return run(paths)
Beispiel #10
0
def _horizontal_edges(aligned_vertices):
    """
    iterate through all horizontal edges (containing segments)
    between given horizontally aligned vertices.
    """
    for index in range(len(aligned_vertices) - 1):
        vertices = [
            aligned_vertices[index],
            aligned_vertices[(index + 1) % len(aligned_vertices)]
        ]
        objects = [v.bound_object for v in vertices]
        yield Edge(*vertices, real_path=Segment(objects))
Beispiel #11
0
 def horizontal_intersections_at(self, intersecting_y, xmin, xmax):
     """
     intersections with horizontal line at given y.
     returns array of points.
     """
     segment = Segment(
         [Point([xmin, intersecting_y]),
          Point([xmax, intersecting_y])])
     intersections = self.intersections_with_segment(segment)
     intersections = [
         Point([i.get_x(), intersecting_y]) for i in intersections
     ]
     return intersections
Beispiel #12
0
def quadratic(size):
    """
    n^2 brute force algorithm
    """
    paths = [
        Segment([Point([2 * i, 0]), Point([2 * i + 1, 0])])
        for i in range(size)
    ]
    start_time = clock()
    for p_1, p_2 in combinations(paths, r=2):
        p_1.intersections_with(p_2)
    end_time = clock()
    return end_time - start_time
Beispiel #13
0
def merge_path(outer_path, inner_path, position):
    """
    merge inner path inside outer path at given position.
    Note that since positions contains array indices you
    need to merge starting from last path.
    """
    paths = outer_path.elementary_paths
    outer_point = position.outer_position.point
    inner_point = position.inner_position.point
    if __debug__:
        if is_module_debugged(__name__):
            print("merging at", position.outer_position.index)
            tycat(outer_path, inner_path,
                  position.outer_position.elementary_path)
    arrival_path = paths[position.outer_position.index]
    assert arrival_path.contains(outer_point), "no merging here"

    sub_path = []
    before, after = arrival_path.split_around(outer_point)
    if before is not None:
        sub_path.append(before)

    if not outer_point.is_almost(inner_point):
        sub_path.append(Segment([outer_point, inner_point]))

    sub_path.append(VerticalPath(-1))
    sub_path.extend(inner_path.elementary_paths)
    sub_path.append(VerticalPath(1))

    if not outer_point.is_almost(inner_point):
        sub_path.append(Segment([inner_point, outer_point]))

    if after is not None:
        sub_path.append(after)

    paths[position.outer_position.index:position.outer_position.index] = \
        sub_path
    outer_path.set_elementary_paths(paths)
Beispiel #14
0
def border_2d(stl_model, margin):
    """
    return 2d enclosing (starting at origin) for given model and margin.
    """
    # build four points
    xmin, ymin = 0, 0
    xmax, ymax = stl_model.dimensions(margin)
    points = []
    points.append(Point([xmin, ymin]))
    points.append(Point([xmin, ymax]))
    points.append(Point([xmax, ymax]))
    points.append(Point([xmax, ymin]))

    return [Segment([p, q]) for p, q in all_two_elements(points)]
Beispiel #15
0
 def displace(cls, path, distance):
     """
     displace given path by given distance on outer side.
     """
     if isinstance(path, Segment):
         parallel_segment = path.parallel_segment(distance, -1)
         hashed_segment = Segment(
             [ROUNDER2D.hash_point(p) for p in parallel_segment.endpoints])
         return cls(hashed_segment, path)
     else:
         if path.reversed_direction:
             new_radius = 2 * path.radius
             new_points = [p * 2 - path.center for p in path.endpoints]
             hashed_points = [ROUNDER2D.hash_point(p) for p in new_points]
             inflated_path = Arc(new_radius, hashed_points, path.center,
                                 True)
         else:
             inflated_path = ROUNDER2D.hash_point(path.center)
         return cls(inflated_path, path)
Beispiel #16
0
    def project(self, point):
        """
        find where point on stored path projects itself on origin.
        """
        if isinstance(self.origin, Point):
            result = self.origin
        elif isinstance(self.origin, Segment):
            result = self.origin.point_projection(point)
        else:
            intersections = self.origin.intersections_with_segment(
                Segment([self.origin.center, point]))
            assert len(intersections) == 1
            result = intersections[0]

        if __debug__:
            if is_module_debugged(__name__):
                print("project from envelope back to original path")
                tycat(self.path, self.origin, point, result)

        return result
Beispiel #17
0
def test(seconds=None):
    """
    intersect a bunch of random segments and display result.
    """
    display = True
    if seconds is None:
        display = False
        seconds = clock()

    seed(float(seconds))

    paths = [
        Segment([
            ROUNDER2D.hash_point(Point([random(), random()])),
            ROUNDER2D.hash_point(Point([random(), random()]))
        ]) for _ in range(10)
    ]
    for _ in range(0):
        center = ROUNDER2D.hash_point(Point([random(), random()]))
        radius = 0
        while radius < 0.02:
            radius = random() / 4
        points = [
            center + ROUNDER2D.hash_point(Point([cos(a), sin(a)]) * radius)
            for a in (random() * 10, random() * 10)
        ]

        paths.append(Arc(radius, points, center).correct_endpoints_order())

    # print(",\n        ".join([str(s) for s in paths]))
    if display:
        tycat(paths)
    try:
        intersections = compute_intersections(paths)
    except:
        print("seed", seconds)
        tycat(paths)
        raise

    intersections.append(paths)
    return intersections
Beispiel #18
0
    def offset(self):
        """
        extend polygon's edges by moving parallel to them
        and reconnect pieces.
        """
        raw_segments = []
        for segment in self.polygon.segments():
            parallel_segment = segment.parallel_segment(self.radius)
            hashed_segment = Segment(
                [ROUNDER2D.hash_point(p) for p in parallel_segment.endpoints])
            raw_segments.append((hashed_segment, segment))

        if __debug__:
            if is_module_debugged(__name__):
                print("unjoined raw segments")
                segments = [t[0] for t in raw_segments]
                tycat(self.polygon, segments)

        try:
            self.join_raw_segments(raw_segments)
        except:
            print("failed joining edges in offsetter")
            segments = [t[0] for t in raw_segments]
            tycat(self.polygon, segments)
            raise

        try:
            # for performance reasons we can remove now the small loop pockets
            # created by sharp angles.
            # they would be removed anyway later on but it is much better
            # to remove them now so they do not appear in the O(n^2) algorithm
            # used later on
            self.remove_loops()
        except:
            print("failed removing loops")
            tycat(self.polygon, self.edge)
            raise

        return self.edge
Beispiel #19
0
def _skip_seen_vertices(cycle):
    """
    change cycle so that we do not pass twice at same vertex
    (except for completing the cycle).
    achieves that by shortcutting to next point using a segment.
    CAREFUL: vertices are not updated in the process.
    """
    seen_vertices = {}
    start = cycle[0].vertices[0]
    current_vertex = start
    seen_vertices[current_vertex] = True
    resulting_cycle = []
    for edge in cycle:
        next_vertex = edge.vertices[1]
        if next_vertex not in seen_vertices:
            if current_vertex == edge.vertices[0]:
                resulting_cycle.append(edge)
            else:
                objects = [
                    v.bound_object for v in (current_vertex, next_vertex)
                ]
                if isinstance(objects[0], Point) \
                        and isinstance(objects[0], Point):
                    point1, point2 = objects
                else:
                    point1, point2 = nearest_points(objects[0], objects[1])

                resulting_cycle.append(
                    Edge(current_vertex, next_vertex, Segment([point1, point2]))
                )
            current_vertex = next_vertex
            seen_vertices[current_vertex] = True

    # add last segment to go back at start
    resulting_cycle.append(cycle[-1])
    return resulting_cycle
Beispiel #20
0
#!/usr/bin/env python3

from jimn.point import Point
from jimn.segment import Segment
from jimn.displayable import tycat

print("**************************")
print("*testing segments overlap*")
print("**************************")

print("non aligned")

s1 = Segment([Point([0, 3]), Point([0, 6])])
s2 = Segment([Point([1, 3]), Point([0, 6])])
tycat(s1, s2)

assert not s1.overlaps(s2)

print("aligned, no overlap")

s1 = Segment([Point([0, 0]), Point([3, 3])])
s2 = Segment([Point([4, 4]), Point([6, 6])])
tycat(s1, s2)

assert not s1.overlaps(s2)

print("overlap, no one disappears")

s1 = Segment([Point([0, 0]), Point([3, 3])])
s2 = Segment([Point([2, 2]), Point([6, 6])])
tycat(s1, s2)
Beispiel #21
0
#!/usr/bin/env python3

from jimn.point import Point
from jimn.segment import Segment
from jimn.polygon import Polygon
from jimn.pocket import Pocket
from jimn.envelope import Envelope
from jimn.arc import Arc
from jimn.displayable import tycat
from jimn.displayable import tycat_start, tycat_end

print("testing intersection")

s = Polygon.square(0, 0, 8)
s = s.orient(False)
path_in = Pocket(list(s.segments()))

path_out = Segment([Point([-3, 3]), Point([12, 5])])

e1 = Envelope(path_in, 1)
e2 = Envelope(path_out, 1)

tycat(e1, e2)

points = e2.junction_points(e1)
tycat(e1, e2, points)
Beispiel #22
0
 def segments(self):
     """
     iterate through all segments.
     """
     for points in all_two_elements(self.points):
         yield Segment(points)
Beispiel #23
0
#!/usr/bin/env python3

from jimn.point import Point
from jimn.segment import Segment
from jimn.displayable import tycat
from math import cos, sin, pi

points = [
    Point([cos((i * 2 * pi) / 8), sin(i * (2 * pi) / 8)]) for i in range(8)
]
tycat(*points)
origin = Point([0, 0])
for p in points:
    print(origin.angle_with(p))

for p in points:
    s = Segment([origin, p])
    tycat(points, s)
    print("key angle is:", s.key_angle())
    print("********************")
Beispiel #24
0
arcs = (Arc(3, [Point([1, 2]), Point([4, -1])],
            Point([4,
                   2])), Arc(3, [Point([3, 3]), Point([6, 0])], Point([6, 3])),
        Arc(3, [Point([4, 3]), Point([7, 0])],
            Point([7,
                   3])), Arc(2, [Point([0, 1]), Point([2, 3])], Point([0, 3])))

print("*** trying intersection with arcs ***")
for i, a in enumerate(arcs):
    print(labels[i])
    intersection = a1.intersections_with_arc(a)
    tycat(a1, a, intersection)

segments = (
    Segment([Point([-1, 2]), Point([3, 1])]),
    Segment([Point([3.2, 3]), Point([0.2, 0])]),
    Segment([Point([5.2, 3]), Point([2.2, 0])]),
    Segment([Point([-1, 0]), Point([3, 0])]),
)
s_labels = (
    "single intersection",
    "double intersection",
    "no intersection",
    "tangent",
)
print("*** trying intersection with segments ***")
for i, s in enumerate(segments):
    print(s_labels[i])
    intersections = a1.intersections_with_segment(s)
    tycat(a1, s, intersections)
Beispiel #25
0
def main():
    s1 = Segment([Point([0, 0]), Point([1, 1])])
    s2 = Segment([Point([0, 0]), Point([1, -1])])
    s3 = Segment([Point([0.5, -2]), Point([0.5, 2])])
    compute_intersections([s1, s2, s3])
Beispiel #26
0
including = Polygon.square(-1, 4, 3)
including_pocket = Pocket(list(including.segments()))

not_including = [
    Point([-2.0, 3.0]),
    Point([-2.0, 2.0]),
    Point([9.0, 2.0]),
    Point([9.0, 10.0]),
    Point([-2.0, 10.0]),
    Point([-2.0, 9.0]),
    Point([8.0, 9.0]),
    Point([8.0, 3.0]),
]

not_including_pocket = Pocket(
    [Segment([a, b]) for a, b in all_two_elements(not_including)])

vertically_aligned = [
    Point([-1, 3.5]),
    Point([2, 3.5]),
    Point([4, 5.5]),
    Point([2, 7.5]),
    Point([-1, 7.5]),
    Point([-4, 5.5]),
]

va_pocket = Pocket(
    [Segment([a, b]) for a, b in all_two_elements(vertically_aligned)])

if tested_pocket.is_included_in(including_pocket):
    print("red is included in green (ok)")