Exemple #1
0
    def from_string(cls, string: str, *args, **kwargs):
        prev_gui_end = kwargs.get('prev_gui_end', Point2())
        prev_gcode_end = kwargs.get('prev_gcode_end', Point2())
        cnc_lines = [Line(l) for l in string.strip().split('\n')]
        assert len(cnc_lines) == 3

        line1, line2, line3 = cnc_lines

        index = line1.gcodes[0].number
        spill = line1.block.modal_params[1].value
        speed = line2.gcodes[0].word.value

        params = line3.gcodes[0].params
        geom_end_point = Point2(params['X'].value, params['Y'].value)

        x = geom_end_point.x
        y = geom_end_point.y

        return cls(index=index,
                   x=x,
                   y=y,
                   speed=speed,
                   spill=spill,
                   prev_gui_end=prev_gui_end,
                   prev_gcode_end=prev_gcode_end)
Exemple #2
0
    def gui_geometry(self):
        x1, y1 = self._gui_p1.x, self._gui_p1.y
        x2, y2 = self._gui_p2.x, self._gui_p2.y
        r = self._r

        xmid = (x1 + x2) / 2
        ymid = (y1 + y2) / 2

        d = math.sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2))
        a = d / 2
        h = math.sqrt(r * r - a * a)

        xcenter = xmid + (h / d) * (y2 - y1)
        ycenter = ymid - (h / d) * (x2 - x1)

        circle = Circle(Point2(xcenter, ycenter), r)
        ray = Ray2(Point2(xmid, ymid), Point2(xcenter, ycenter))

        arc_split_point = circle.intersect(ray).p1

        return [
            Arc(Point2(xcenter, ycenter), self._r, self._gui_p1,
                arc_split_point),
            Arc(Point2(xcenter, ycenter), self._r, arc_split_point,
                self._gui_p2)
        ]
def catmull_rom_spline_variants():
    points = [
        Point2(0,0),
        Point2(1,1),
        Point2(2,1),
        Point2(2,-1),
    ]
    controls = control_points(points)

    # By default, catmull_rom_points() will return a closed smooth shape
    curve_points_closed = catmull_rom_points(points, close_loop=True)

    # If `close_loop` is False, it will return only points between the start and
    # end control points, and make a best guess about tangents for the first and last segments
    curve_points_open   = catmull_rom_points(points, close_loop=False)
    
    # By specifying start_tangent and end_tangent, you can change a shape 
    # significantly. This is similar to what you might do with Illustrator's Pen Tool.
    # Try changing these vectors to see the effects this has on the rightmost curve in the example
    start_tangent = Vector2(-2, 0)
    end_tangent = Vector2(3, 0)
    tangent_pts = [points[0] + start_tangent, *points, points[-1] + end_tangent]
    tangent_controls = control_points(tangent_pts)
    curve_points_tangents = catmull_rom_points(points, close_loop=False, 
                                start_tangent=start_tangent, end_tangent=end_tangent)

    closed = polygon(curve_points_closed) + controls
    opened = polygon(curve_points_open) + controls
    tangents = polygon(curve_points_tangents) + tangent_controls

    a = closed + right(3)(opened) + right(10)(tangents)

    return a
Exemple #4
0
def test_cwarcshortcommand_from_string():
    com = CwShortArcToCommand.from_string(
        string=
        'N001 M500 P0\n     F12000 \n     G02 X-2 Y2 Z0 I.8708286934 J2.8708286934 K0',
        prev_gui_end=Point2(0, 0),
        prev_gcode_end=Point2(0, 0))

    expect(com.command_type).to_equal(CommandType.CW_ARC_TO_SHORT)
    expect([com[i] for i in range(10)
            ]).to_equal([1, 'CW Arc To', -2.0, 2.0, 3.0, 0, 12000, 0, '', ''])
    expect(com.is_move).to_equal(True)
    expect(com.disabled).to_equal((8, 9))

    gui = com.gui_geometry[-1]
    expect(len(com.gui_geometry)).to_equal(1)
    expect(gui.p1).to_equal(Point2(0, 0))
    expect(gui.p2).to_equal(Point2(-2.0, 2.0))
    expect(type(gui)).to_be(Arc)
    expect(gui.c.x).almost_equal(0.871, 0.01)
    expect(gui.c.y).almost_equal(2.871, 0.01)
    expect(gui.r).almost_equal(3, 0.01)

    expect(com.length).almost_equal(2.95, 0.01)

    expect(com.gcode_end_x).to_equal(-2.0)
    expect(com.gcode_end_y).to_equal(2.0)

    expect(com.as_gcode).to_equal(
        'N001 M500 P0.0\n     F12000\n     G02 X-2.000 Y2.000 Z0 I0.871 J2.871 K0\n'
    )
Exemple #5
0
 def test_euclidify_non_mutating(self):
     base_tri = [Point2(0, 0), Point2(10, 0), Point2(0, 10)]
     next_tri = euclidify(base_tri, Point2)
     expected = 3
     actual = len(base_tri)
     self.assertEqual(expected, actual,
                      'euclidify should not mutate its arguments')
Exemple #6
0
def test_cwarcshortcommand_constructor():
    com = CwShortArcToCommand(1, 5.0, 3.0, 4.0, 12000, 0.0, Point2(0, 0),
                              Point2(0, 0))

    expect(com.command_type).to_equal(CommandType.CW_ARC_TO_SHORT)
    expect([com[i] for i in range(10)
            ]).to_equal([1, 'CW Arc To', 5.0, 3.0, 4.0, 0, 12000, 0, '', ''])
    expect(com.is_move).to_equal(True)
    expect(com.disabled).to_equal((8, 9))

    gui = com.gui_geometry[-1]
    expect(len(com.gui_geometry)).to_equal(1)
    expect(gui.p1).to_equal(Point2(0, 0))
    expect(gui.p2).to_equal(Point2(5.0, 3.0))
    expect(type(gui)).to_be(Arc)
    expect(gui.c.x).almost_equal(3.909, 0.01)
    expect(gui.c.y).almost_equal(-0.84, 0.01)
    expect(gui.r).almost_equal(4, 0.01)

    expect(com.length).almost_equal(6.53, 0.01)

    expect(com.gcode_end_x).to_equal(5.0)
    expect(com.gcode_end_y).to_equal(3.0)

    expect(com.as_gcode).to_equal(
        'N001 M500 P0.0\n     F12000\n     G02 X5.000 Y3.000 Z0 I3.909 J-0.848 K0\n'
    )
Exemple #7
0
def test_center_point_arbitrary_begin_obtuse_angle_right_first_q():
    begin = LineSegment2(Point2(0, 0), Point2(1, 5))
    end = LineSegment2(Point2(1, 5), Point2(5, 7))
    diameter = 2

    int1, int2, int3, int4 = get_intersects(begin, end, diameter=diameter)
    expect(int4.x).almost_equal(2.76, 0.01)
    expect(int4.y).almost_equal(3.64, 0.01)
Exemple #8
0
def test_center_point_vertical_begin_acute_angle_right_first_q():
    begin = LineSegment2(Point2(0, 0), Point2(0, 5))
    end = LineSegment2(Point2(0, 5), Point2(7, 0))
    diameter = 2

    int1, int2, int3, int4 = get_intersects(begin, end, diameter=diameter)
    expect(int4.x).to_equal(2)
    expect(int4.y).almost_equal(1.11, 0.01)
Exemple #9
0
 def test_path_2d(self):
     base_tri = [Point2(0, 0), Point2(10, 0), Point2(10, 10)]
     actual = euc_to_arr(path_2d(base_tri, width=2, closed=False))
     expected = [
         [0.0, 1.0], [9.0, 1.0], [9.0, 10.0], 
         [11.0, 10.0], [11.0, -1.0], [0.0, -1.0]
     ]
     self.assertEqual(expected, actual)
Exemple #10
0
def test_center_point_horizontal_begin_right_angle_right_second_q():
    begin = LineSegment2(Point2(0, 0), Point2(-5, 0))
    end = LineSegment2(Point2(-5, 0), Point2(-5, 5))
    diameter = 2

    int1, int2, int3, int4 = get_intersects(begin, end, diameter=diameter)

    expect(int2.x).to_equal(-3)
    expect(int2.y).to_equal(2)
Exemple #11
0
 def test_bezier_points(self):
     expected = [
         Point2(0.00, 0.00),
         Point2(1.38, 0.62),
         Point2(2.00, -1.00)
     ]
     actual = bezier_points(self.bezier_controls,
                            subdivisions=self.subdivisions)
     self.assertPointsListsEqual(expected, actual)
Exemple #12
0
def test_center_point_horizontal_begin_acute_angle_right_second_q():
    begin = LineSegment2(Point2(0, 0), Point2(-5, 0))
    end = LineSegment2(Point2(-5, 0), Point2(-1, 5))
    diameter = 2

    int1, int2, int3, int4 = get_intersects(begin, end, diameter=diameter)

    expect(int2.x).almost_equal(-0.83, 0.01)
    expect(int2.y).almost_equal(2.0, 0.01)
Exemple #13
0
def create_left_buttom_circle():
    p0 = switches.get_cap_corner((0, 1), Point2(0.5, -0.5))
    p1 = switches.get_cap_corner((1, 1), Point2(0.5, -0.5))
    p2 = switches.get_cap_corner((3, 1), Point2(0, -0.62))
    circle = utils.three_point_cicle(p0,
                                     p1,
                                     p2,
                                     radius_adjustment=1.5 * mm,
                                     segments=1000)
    right_edge = switches.get_cap_corner(Point2(0, 0), Point2(-0.5, 0.5)).x
    return circle * sc.square(right_edge * 2, center=True)
def basic_bezier():
    # A basic cubic Bezier curve will pass through its first and last 
    # points, but not through the central control points
    controls = [
        Point2(0, 3),
        Point2(1, 1),
        Point2(2, 1),
        Point2(3, 3)
    ]
    shape = bezier_polygon(controls, show_controls=True)
    return shape
Exemple #15
0
 def test_bezier_points_raw(self):
     # Verify that we can use raw sequences of floats as inputs (e.g [(1,2), (3.2,4)])
     # rather than sequences of Point2s
     expected = [
         Point2(0.00, 0.00),
         Point2(1.38, 0.62),
         Point2(2.00, -1.00)
     ]
     actual = bezier_points(self.bezier_controls_raw,
                            subdivisions=self.subdivisions)
     self.assertPointsListsEqual(expected, actual)
Exemple #16
0
 def test_extrude_along_path_2d_scale(self):
     # verify that we can apply differential x & y scaling
     path = [[0, 0, 0], [0, 20, 0], [0, 40, 0]]
     scales_2d = [
         Point2(1, 1),
         Point2(0.5, 1.5),
         Point2(1.5, 0.5),
     ]
     actual = extrude_along_path(tri, path, scales=scales_2d)
     expected = 'polyhedron(faces=[[0,3,1],[1,3,4],[1,4,2],[2,4,5],[2,5,0],[0,5,3],[3,6,4],[4,6,7],[4,7,5],[5,7,8],[5,8,3],[3,8,6],[9,0,1],[9,1,2],[9,2,0],[10,6,7],[10,7,8],[10,8,6]],points=[[0.0000000000,0.0000000000,0.0000000000],[10.0000000000,0.0000000000,0.0000000000],[0.0000000000,0.0000000000,10.0000000000],[0.0000000000,20.0000000000,0.0000000000],[5.0000000000,20.0000000000,0.0000000000],[0.0000000000,20.0000000000,15.0000000000],[0.0000000000,40.0000000000,0.0000000000],[15.0000000000,40.0000000000,0.0000000000],[0.0000000000,40.0000000000,5.0000000000],[3.3333333333,0.0000000000,3.3333333333],[5.0000000000,40.0000000000,1.6666666667]]);'
     self.assertEqualOpenScadObject(expected, actual)
Exemple #17
0
    def test_path_2d_polygon(self):
        base_tri = [Point2(0, 0), Point2(10, 0), Point2(10, 10), Point2(0, 10)]
        poly = path_2d_polygon(base_tri, width=2, closed=True)
        expected = [(1.0, 1.0), (9.0, 1.0), (9.0, 9.0), (1.0, 9.0),
                    (-1.0, 11.0), (11.0, 11.0), (11.0, -1.0), (-1.0, -1.0)]
        actual = euc_to_arr(poly.params['points'])
        self.assertEqual(expected, actual)

        # Make sure the inner and outer paths in the polygon are disjoint
        expected = [[0, 1, 2, 3], [4, 5, 6, 7]]
        actual = poly.params['paths']
        self.assertEqual(expected, actual)
Exemple #18
0
 def test_catmull_rom_points(self):
     expected = [
         Point2(0.00, 0.00),
         Point2(0.38, 0.44),
         Point2(1.00, 1.00),
         Point2(1.62, 1.06),
         Point2(2.00, 1.00)
     ]
     actual = catmull_rom_points(self.points,
                                 subdivisions=self.subdivisions,
                                 close_loop=False)
     self.assertPointsListsEqual(expected, actual)
def basic_catmull_rom():
    points = [
        Point2(0,0),
        Point2(1,1),
        Point2(2,1),
        Point2(2,-1),
    ]
    # In its simplest form, catmull_rom_polygon() will just make a C1-continuous
    # closed shape. Easy.
    shape_easy = catmull_rom_polygon(points)
    # There are some other options as well...
    shape = catmull_rom_polygon(points, subdivisions=20, extrude_height=5, show_controls=True)
    return shape_easy + right(3)(shape)
Exemple #20
0
def get_parallel_lines(line, diameter):
    x1, y1 = line.p1
    x2, y2 = line.p2

    a = y1 - y2
    b = x2 - x1
    c = (x1 * y2 - x2 * y1)

    if b != 0:
        k = -a / b
        m = -c / b

        # y = m*x + c + d*sqrt(1+m^2);
        par_above = lambda xnew: k * xnew + m + diameter * math.sqrt(1 + k * k)
        par_below = lambda xnew: k * xnew + m - diameter * math.sqrt(1 + k * k)

        line_above = Line2(Point2(x1, par_above(x1)),
                           Point2(x2, par_above(x2)))
        line_below = Line2(Point2(x1, par_below(x1)),
                           Point2(x2, par_below(x2)))
    else:
        line_above = Line2(Point2(x1 - diameter, y1),
                           Point2(x2 - diameter, y2))
        line_below = Line2(Point2(x1 + diameter, y1),
                           Point2(x2 + diameter, y2))

    return line_above, line_below
Exemple #21
0
 def test_catmull_rom_points_raw(self):
     # Verify that we can use raw sequences of floats as inputs (e.g [(1,2), (3.2,4)])
     # rather than sequences of Point2s
     expected = [
         Point2(0.00, 0.00),
         Point2(0.38, 0.44),
         Point2(1.00, 1.00),
         Point2(1.62, 1.06),
         Point2(2.00, 1.00)
     ]
     actual = catmull_rom_points(self.points_raw,
                                 subdivisions=self.subdivisions,
                                 close_loop=False)
     self.assertPointsListsEqual(expected, actual)
Exemple #22
0
def test_center_point_horizontal_begin_obtuse_angle_right_second_q():
    begin = LineSegment2(Point2(0, 0), Point2(-5, 0))
    end = LineSegment2(Point2(-5, 0), Point2(-7, 5))
    diameter = 2

    int1, int2, int3, int4 = get_intersects(begin, end, diameter=diameter)

    print('\n')
    print(int1)
    print(int2)
    print(int3)
    print(int4)

    expect(int1.x).almost_equal(-3.64, 0.01)
    expect(int1.y).almost_equal(2.0, 0.01)
Exemple #23
0
def _catmull_rom_segment(controls: FourPoints,
                         subdivisions: int,
                         include_last=False) -> List[Point23]:
    """
    Returns `subdivisions` Points between the 2nd & 3rd elements of `controls`,
    on a quadratic curve that passes through all 4 control points.
    If `include_last` is True, return `subdivisions` + 1 points, the last being
    controls[2]. 

    No reason to call this unless you're trying to do something very specific
    """
    pos: Point23 = None
    positions: List[Point23] = []

    num_points = subdivisions
    if include_last:
        num_points += 1

    p0, p1, p2, p3 = [euclidify(p, Point2) for p in controls]
    a = 2 * p1
    b = p2 - p0
    c = 2 * p0 - 5 * p1 + 4 * p2 - p3
    d = -p0 + 3 * p1 - 3 * p2 + p3

    for i in range(num_points):
        t = i / subdivisions
        pos = 0.5 * (a + (b * t) + (c * t * t) + (d * t * t * t))
        positions.append(Point2(*pos))
    return positions
def extrude_example_xy_scaling() -> OpenSCADObject:
    num_points = SEGMENTS
    path_rad = PATH_RAD
    circle = circle_points(15)
    path = circle_points(rad=path_rad)

    # If scales aren't included, they'll default to
    # no scaling at each step along path.
    no_scale_obj = make_label('No Scale')
    no_scale_obj += extrude_along_path(circle, path)

    # angles: from 0 to 6*Pi
    angles = list((frange(0, 3 * tau, num_steps=len(path))))

    # With a 1-D scale factor, an extrusion grows and shrinks uniformly
    x_scales = [(1 + cos(a) / 2) for a in angles]
    x_obj = make_label('1D Scale')
    x_obj += extrude_along_path(circle, path, scales=x_scales)

    # With a 2D scale factor, a shape's X & Y dimensions can scale
    # independently, leading to more interesting shapes
    # X & Y scales vary between 0.5 & 1.5
    xy_scales = [Point2(1 + cos(a) / 2, 1 + sin(a) / 2) for a in angles]
    xy_obj = make_label('2D Scale')
    xy_obj += extrude_along_path(circle, path, scales=xy_scales)

    obj = no_scale_obj + right(3 * path_rad)(x_obj) + right(
        6 * path_rad)(xy_obj)
    return obj
Exemple #25
0
    def gcode_geometry(self):
        # gui_line = self.gui_geometry[-1]
        # next_line = self.next_segment

        gui_line = LineSegment2(Point2(7, 10), Point2(7, 15))
        next_line = LineSegment2(Point2(7, 15), Point2(0, 20))

        right_hand = not is_left(gui_line, next_line.p2)
        arc_command = 'G02' if right_hand else 'G03'

        d = 3
        intersect1, intersect2, intersect3, intersect4 = get_intersects(
            gui_line, next_line, diameter=d)
        inter = intersect4 if right_hand else intersect2

        return self.gui_geometry
Exemple #26
0
def _point_along_bez4(p0: Point23, p1: Point23, p2: Point23, p3: Point23,
                      u: float) -> Point2:
    x = _bez03(u) * p0.x + _bez13(u) * p1.x + _bez23(u) * p2.x + _bez33(
        u) * p3.x
    y = _bez03(u) * p0.y + _bez13(u) * p1.y + _bez23(u) * p2.y + _bez33(
        u) * p3.y
    return Point2(x, y)
Exemple #27
0
def test_linetowithendcurvecommand_constructor():
    com = LineToWithEndCurveCommand(2, 7.0, 12.0, 2, 12000, 0,
                                    Point2(0.0, 5.0), Point2(0.0, 5.0))

    expect(com.command_type).to_equal(CommandType.LINE_TO_END)
    expect([com[i] for i in range(10)
            ]).to_equal([2, 'Line To', 7.0, 12.0, 2.0, '', 12000, 0, '', ''])
    expect(com.is_move).to_equal(True)
    # expect(com.length).almost_equal(14.14, 0.01)
    # expect(com.disabled).to_equal((5, 8, 9))

    # gui = com.gui_geometry[-1]
    # expect(gui.p1).to_equal(Point2(0, 0))
    # expect(gui.p2).to_equal(Point2(10, 10))
    #
    gcode = com.gcode_geometry[-1]
Exemple #28
0
def all_solutions_point2(solver: z3.Solver,
                         fillet_center) -> typing.List[Point2]:
    solutions = []
    x, y = fillet_center
    while solver.check() == z3.sat:
        m = solver.model()
        solution = Point2(solution_as_float(m[x]), solution_as_float(m[y]))
        solutions.append(solution)
        solver.add((x - solution.x)**2 +
                   (y - solution.y)**2 > 10**(-PRECISION) * 100)
    return solutions
Exemple #29
0
def _point_along_bez4(p0: Point23List, p1: Point23List, p2: Point23List,
                      p3: Point23List, u: float) -> Point2:
    p0 = euclidify(p0)
    p1 = euclidify(p1)
    p2 = euclidify(p2)
    p3 = euclidify(p3)

    x = _bez03(u) * p0.x + _bez13(u) * p1.x + _bez23(u) * p2.x + _bez33(
        u) * p3.x
    y = _bez03(u) * p0.y + _bez13(u) * p1.y + _bez23(u) * p2.y + _bez33(
        u) * p3.y
    return Point2(x, y)
Exemple #30
0
def create_upper_case():
    p0 = switches.get_switch_position((0, 3)) + Point2(-0.5, 0.5)
    p1 = switches.get_switch_position((2, 3)) + Point2(-0.5, 0.5)
    p2 = switches.get_switch_position((4, 3)) + Point2(0.5, 0.5)
    case = utils.three_point_cicle(p0,
                                   p1,
                                   p2,
                                   radius_adjustment=-1.5 * mm,
                                   segments=1000)
    # cut left edge
    case = case * sc.translate(
        (utils.big_cutter_length - 0.5, 0, 0))(utils.big_cutter_square)
    # cut right edge
    case = case * sc.translate(
        (-utils.big_cutter_length + 4.5, 0, 0))(utils.big_cutter_square)
    # cut buttom edge
    _, buttom_left_switch_y = switches.get_switch_position((0, 1))
    case = case * sc.translate(
        (0, utils.big_cutter_length + buttom_left_switch_y - 0.5, 0))(
            utils.big_cutter_square)
    return case