コード例 #1
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))
コード例 #2
0
ファイル: segment.py プロジェクト: wagnerf42/Jimn
    def clip(self, center, size):
        """
        clip self in square of given size at given center.
        """
        # TODO move in elementary path
        points = [
            center + Point([-size, -size]),
            center + Point([size, -size]),
            center + Point([size, size]),
            center + Point([-size, size]),
        ]
        segments = [Segment([a, b]) for a, b in all_two_elements(points)]
        intersections = []
        for segment in segments:
            intersection = segment.intersection_with_segment(self)
            if intersection:
                intersections.append(intersection)

        box = BoundingBox.empty_box(2)
        box.add_point(points[0])
        box.add_point(points[2])

        for chunk in self.split_at(intersections):
            middle = (chunk.endpoints[0] + chunk.endpoints[1]) / 2
            if box.almost_contains_point(middle):
                return chunk
コード例 #3
0
def main():
    """
    launches all benchmars ; logs on stdout
    """
    system("git rev-parse HEAD")
    start = clock()
    points = [Point([random(), random()]) for _ in range(100000)]
    end = clock()
    print("created", len(points), "points in", end - start)
    start = clock()
    rounder = CoordinatesHash(5)
    for point in points:
        rounder.hash_point(point)
    end = clock()
    print("hashed", len(points), "points in", end - start)
    start = clock()
    model = Stl("../test_files/cordoba.stl")
    model.compute_slices(0.3, Point([0.0, 0.0]))
    end = clock()
    print("slicing small file in", end - start)
    start = clock()
    model = Stl("../test_files/cordoba-very-large.stl")
    model.compute_slices(0.1, Point([0.0, 0.0]))
    end = clock()
    print("slicing large file in", end - start)
    start = clock()
    compute_milling_path("../test_files/cordoba.stl", 0.3, 0.3)
    end = clock()
    print("easy instance in", end - start)
    start = clock()
    compute_milling_path("../test_files/cordoba-very-large.stl", 0.1, 0.1)
    end = clock()
    print("difficult instance in", end - start)
コード例 #4
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)
コード例 #5
0
 def get_bounding_box(self):
     """
     bounding box for arc.
     for now, not tight
     """
     box = BoundingBox.empty_box(2)
     box.add_point(self.center + Point([self.radius, self.radius]))
     box.add_point(self.center - Point([self.radius, self.radius]))
     return box
コード例 #6
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)
コード例 #7
0
ファイル: segment.py プロジェクト: wagnerf42/Jimn
 def horizontal_intersection_at(self, intersecting_y):
     """
     return point on self at given y.
     precondition : y is valid height in segment.
     """
     (x_1, y_1), (x_2, y_2) = [p.coordinates for p in self.endpoints]
     if is_almost(x_1, x_2):
         return Point([x_1, intersecting_y])
     else:
         slope = (y_1 - y_2) / (x_1 - x_2)
         intersecting_x = (intersecting_y - y_1) / slope + x_1
         return Point([intersecting_x, intersecting_y])
コード例 #8
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
コード例 #9
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
コード例 #10
0
def vline_circle_intersections(x, center, radius):
    """
    intersection of circle with vertical line at given x.
    """
    distance = abs(x - center.get_x())
    if is_almost(radius, distance):
        return [Point([x, center.get_y()])]
    squared_distance = distance * distance
    squared_radius = radius * radius
    if squared_distance > squared_radius:
        return []
    y = sqrt(squared_radius - squared_distance)
    return [Point([x, center.get_y() + y]), Point([x, center.get_y() - y])]
コード例 #11
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)]
コード例 #12
0
ファイル: segment.py プロジェクト: wagnerf42/Jimn
 def line_hash(self):
     """
     return unique id of line on which is segment.
     nearly aligned segments will hash
     on same value.
     """
     (x_1, y_1), (x_2, y_2) = [p.coordinates for p in self.endpoints]
     if is_almost(x_1, x_2):
         return str(LINES_ROUNDER.hash_point(Point([x_1])))
     else:
         slope = (y_2 - y_1) / (x_2 - x_1)
         height_at_origin = y_1 - slope * x_1
         return str(
             LINES_ROUNDER.hash_point(Point([slope, height_at_origin])))
コード例 #13
0
 def square(cls, start_x, start_y, side):
     """
     create a square, horizontally aligned.
     used in many test scripts as a quick way to get polygons.
     """
     starting_point = Point([start_x, start_y])
     points = [
         Point([0.0, 0.0]),
         Point([side, 0.0]),
         Point([side, side]),
         Point([0.0, side]),
     ]
     points = [p + starting_point for p in points]
     square_polygon = cls(points)
     return square_polygon
コード例 #14
0
ファイル: __init__.py プロジェクト: wagnerf42/Jimn
 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
コード例 #15
0
ファイル: stl.py プロジェクト: wagnerf42/Jimn
 def translation_vector(self, margin):
     """
     return translation vector to apply to all points
     to have border min point in (0, 0).
     """
     xmin, ymin = self.bounding_box.min_coordinates[0:2]
     return Point([margin - xmin, margin - ymin])
コード例 #16
0
ファイル: __init__.py プロジェクト: wagnerf42/Jimn
 def translate(self, translation):
     """
     translates the whole pocket by a given translation vector.
     returns new pocket if obtained pocket is different and same pocket
     if translation vector is (0,0)
     """
     if translation.is_almost(Point([0, 0])):
         return self
     return Pocket([p.translate(translation) for p in self.paths])
コード例 #17
0
 def translate(self, translation):
     """
     translates the whole path by a given translation vector.
     returns new path if obtained path is different and same path
     if translation vector is (0,0)
     """
     if translation.is_almost(Point([0, 0])):
         return self
     return Path([p.translate(translation) for p in self.elementary_paths])
コード例 #18
0
ファイル: segment.py プロジェクト: wagnerf42/Jimn
 def parallel_segment(self, distance, side=1):
     """
     return segment parallel to self at given distance,
     on given side. this operation might lead to precision problems.
     keep in mind that if you have three nearly aligned points, by
     taking parallel segments you might obtain four non-aligned points.
     """
     angle = self.endpoints[0].angle_with(self.endpoints[1])
     angle += side * pi / 2
     displacement = Point([distance * cos(-angle), distance * sin(-angle)])
     return Segment([p + displacement for p in self.endpoints])
コード例 #19
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
コード例 #20
0
 def save_svg_content(self, display, color):
     """
     svg code for displaying box.
     pre-requisite: 2d box
     """
     points = [
         Point(list(self.min_coordinates)),
         Point(list(self.max_coordinates))
     ]
     coordinates = [
         display.convert_coordinates(p.coordinates) for p in points
     ]
     stroke_width = display.stroke_width()
     for indices in (((0, 0), (0, 1)), ((0, 1), (1, 1)), ((1, 1), (1, 0)),
                     ((1, 0), (0, 0))):
         display.write("<line x1=\"{}\" y1=\"{}\"\
                       x2=\"{}\" y2=\"{}\"".format(
             coordinates[indices[0][0]][0], coordinates[indices[0][1]][1],
             coordinates[indices[1][0]][0], coordinates[indices[1][1]][1]))
         display.write(" stroke-width=\"{}\" stroke=\"{}\"\
                       opacity=\"0.5\"/>\n".format(stroke_width, color))
コード例 #21
0
def circles_intersections(c1, c2, r1, r2):
    """
    intersect two circles with given centers and radiuses.
    return points array.
    """
    d = c1.distance_to(c2)
    if is_almost(d, 0):
        return []  # common center
    x1, y1, x2, y2 = [c for p in (c1, c2) for c in p.coordinates]
    if is_almost(r1, r2):
        l = d/2
    else:
        l = (r1 * r1 - r2 * r2) / (2 * d) + d/2

    if is_almost(r1, l):
        # only one intersection
        i = Point([
            l/d * (x2 - x1) + x1,
            l/d * (y2 - y1) + y1
        ])
        return [i]
    else:
        if r1 < l:
            return []  # too far away

        if abs(r1) < abs(l):
            return []
        else:
            h = sqrt(r1 * r1 - l * l)
            points = [
                Point([
                    l/d * (x2 - x1) + h/d * (y2 - y1) + x1,
                    l/d * (y2 - y1) - h/d * (x2 - x1) + y1
                ]),
                Point([
                    l/d * (x2 - x1) - h/d * (y2 - y1) + x1,
                    l/d * (y2 - y1) + h/d * (x2 - x1) + y1
                ])
            ]
            return points
コード例 #22
0
ファイル: coordinates_hash.py プロジェクト: wagnerf42/Jimn
    def hash_point(self, point):
        """
        add a point to the hash.
        if a nearby point is already hashed do not hash but return
        nearby point.
        """
        if point in self.fast_hash:
            return point

        new_coordinates = [self.hash_coordinate(c, i) for i, c in enumerate(point.coordinates)]
        new_point = Point(new_coordinates)

        self.fast_hash.add(new_point)
        return new_point
コード例 #23
0
def __adjust_point(self, milling_diameter):
    """
    if point is close enough from a milling height, return new point
    exactly at milling height.
    else return point.
    """
    point_y = self.get_y()
    above_height = milling_diameter * floor(point_y / milling_diameter)
    below_height = milling_diameter * ceil(point_y / milling_diameter)
    for height in (above_height, below_height):
        if is_almost(point_y, height):
            return Point([self.get_x(), height])

    return self
コード例 #24
0
ファイル: __init__.py プロジェクト: wagnerf42/Jimn
 def global_path(self, milling_radius):
     """
     flatten the tree into final path.
     """
     # switch back to real tree
     self = self.uncompress(Point([0, 0]))
     # start by computing toplevel tour
     if len(self.children) > 20:
         toplevel_tour = self._compute_toplevel_tour_fast()
     else:
         toplevel_tour = self._compute_toplevel_tour()
     # now, process all subtrees
     for child in self.children:
         child.merge_paths(milling_radius)
     return self._merge_toplevel(toplevel_tour)
コード例 #25
0
ファイル: stl.py プロジェクト: wagnerf42/Jimn
    def _parse_ascii_points(self, points_strings):
        points = []
        for point_string in points_strings:
            matches = re.search(
                r"^\s*(-?\d+(\.\d+)?)\s+(-?\d+(\.\d+)?)\s+(-?\d+(\.\d+)?)",
                point_string)
            coordinates = [
                float(matches.group(1)),
                float(matches.group(3)),
                float(matches.group(5))
            ]
            coordinates[2] = self.heights_hash.hash_coordinate(coordinates[2])

            point = Point(coordinates)
            self.bounding_box.add_point(point)
            points.append(point)

        self.facets.append(Facet(points))
コード例 #26
0
def compute_arc_centers(radius, points):
    """
    return list of possible centers for an arc of given radius going
    through given points.
    """
    # take points[0] as origin
    point2 = points[1] - points[0]
    # find bisector
    middle = point2/2
    bisector_point = middle + point2.perpendicular_vector()
    # intersect with circle at origin
    intersections = line_circle_intersections(
        [middle, bisector_point],
        Point([0, 0]),
        radius
    )
    assert len(intersections) == 2, "invalid arc"
    centers = [points[0] + i for i in intersections]
    return centers
コード例 #27
0
 def horizontal_split(self):
     """
     split ourselves on arcs such that for any given x, each arc
     only has one point.
     return array of sub-arcs.
     """
     extreme_points = [
         self.center + Point([f * self.radius, 0]) for f in (-1, 1)
     ]
     for extremum in extreme_points:
         if self.endpoints[0].is_almost(extremum) or\
                 self.endpoints[1].is_almost(extremum):
             continue
         if self.contains(extremum):
             return [
                 Arc(self.radius, [self.endpoints[0], extremum],
                     self.center, self.reversed_direction),
                 Arc(self.radius, [extremum, self.endpoints[1]],
                     self.center, self.reversed_direction)
             ]
     return [self]
コード例 #28
0
ファイル: __init__.py プロジェクト: wagnerf42/Jimn
    def inside_point_not_on(self, x_hash):
        """
        return a random point STRICTLY inside pocket whose
        x coordinate is not in given hash.
        """
        # take a x coordinate not in given hash
        x_coordinates = [
            p.coordinates[0] for path in self.paths for p in path.endpoints
        ]
        xmin = min(x_coordinates)
        xmax = max(x_coordinates)
        chosen_x = None
        while chosen_x is None or x_hash.contains_coordinate(chosen_x):
            factor = random()
            chosen_x = xmin * factor + (1 - factor) * xmax

        # now, intersect vertically
        # to figure which y ranges are on the inside
        intersections = sorted(self.vertical_intersections(chosen_x))
        # take point in first range
        chosen_y = (intersections[0] + intersections[1]) / 2
        return Point([chosen_x, chosen_y])
コード例 #29
0
    def sweeping_key(self, current_x):
        """
        return key used in sweeping line algorithms for comparing paths.
        key is : intersection with vline at current_x, direction angle
        leaving intersection (following tangent), final angle (towards
        destination)
        """
        if __debug__:
            x_coordinates = sorted([p.get_x() for p in self.endpoints])
            if not x_coordinates[0] <= current_x <= x_coordinates[1]:
                print("path is", self, "current x is:", current_x)
                raise Exception("non comparable paths in tree")

        # start by finding the path's y for current x
        point_key = Point(
            [current_x, self.vertical_intersection_at(current_x)])

        if self.endpoints[0] < self.endpoints[1]:
            first_point, last_point = self.endpoints
        else:
            last_point, first_point = self.endpoints

        terminal_angle = (pi / 2 - first_point.angle_with(last_point)) % pi

        # we need to round so that segments tangent to some arcs
        # will get exact same angles
        # TODO: why 10 ?
        outgoing_angle = round((pi - self.center.angle_with(point_key)) % pi,
                               10)
        angles = (outgoing_angle, terminal_angle)

        # now just reverse angles based on direction
        if last_point.is_almost(point_key):
            full_key = (point_key, -angles[0], -angles[1])
        else:
            full_key = (point_key, angles[0], angles[1])
        return full_key
コード例 #30
0
ファイル: __init__.py プロジェクト: wagnerf42/Jimn
    def __init__(self, paths, cut_arcs=False):
        """
        prepare for sweeping line algorithm on a set of paths.
        """
        # sweeping line algorithms are based on events
        # each event is meeting a new point
        self.events = SortedListWithKey(
            key=lambda t: t[1].sweeping_key(t[0].get_x()))

        if cut_arcs:
            self._add_cut_arcs(paths)
        else:
            for path in paths:
                self.events.add((min(path.endpoints), path))

        self.current_point = None  # current point in sweeping movement

        # visible paths at current_point
        # we put a sentinel as root node whose key values at +infinity
        self.crossed_paths = Treap(
            (Point([float("+inf"), float("+inf")]), 0, 0), root_node=True)
        self.crossed_paths.set_comparer(self)

        self._run()