Esempio n. 1
0
def vertical_finger(length, thickness, finger_play, amount):
    #   creates _vfa and it's counterpart _vfb
    #   _vfa is starts at 0,0
    #   _wfb is _wfa offset vertically by one length
    #   takes in the
    #   length = length of the mortise
    #   thickness = thickness of the material
    #   fingerplay = tolerance in length of the finger for smooth fit
    #   amount = amount of fingers

    for i in range(amount):
        mortise(length,
                thickness,
                finger_play,
                0,
                i * 2 * length + length / 2,
                rotation=math.pi / 2)
        simple.active_name("_height_finger")

    simple.join_multiple("_height_finger")
    simple.active_name("_vfa")
    bpy.ops.object.duplicate_move(
        OBJECT_OT_duplicate={
            "linked": False,
            "mode": 'TRANSLATION'
        },
        TRANSFORM_OT_translate={"value": (0, -length, 0.0)})
    simple.active_name("_vfb")
Esempio n. 2
0
def finger_pair(name, dx=0, dy=0):
    simple.make_active(name)

    xpos = (dx / 2) * 1.006
    ypos = 1.006 * dy / 2

    bpy.ops.object.duplicate_move(
        OBJECT_OT_duplicate={
            "linked": False,
            "mode": 'TRANSLATION'
        },
        TRANSFORM_OT_translate={"value": (xpos, ypos, 0.0)})
    simple.active_name("_finger_pair")

    simple.make_active(name)

    bpy.ops.object.duplicate_move(
        OBJECT_OT_duplicate={
            "linked": False,
            "mode": 'TRANSLATION'
        },
        TRANSFORM_OT_translate={"value": (-xpos, -ypos, 0.0)})
    simple.active_name("_finger_pair")
    simple.join_multiple("_finger_pair")
    bpy.ops.object.select_all(action='DESELECT')
    return bpy.context.active_object
Esempio n. 3
0
def make_variable_flex_pocket(height, finger_thick, pocket_width, locations):
    #   creates pockets pocket using mortise function for kerf bending
    for dist in locations:
        mortise(height - 2 * finger_thick, pocket_width, 0, dist, 0,
                math.pi / 2)
        simple.active_name("_flex_pocket")

    simple.join_multiple("_flex_pocket")
    simple.active_name("flex_pocket")
Esempio n. 4
0
def fixed_finger(loop,
                 loop_length,
                 finger_size,
                 finger_thick,
                 finger_tolerance,
                 base=False):
    #   distributes mortises of a fixed distance
    #   dynamically changes the finger tolerance with the angle differences
    #   loop = takes in a shapely shape
    #   finger_size = size of the mortise
    #   finger_thick = thickness of the material
    #   finger_tolerance = minimum finger tolerance

    coords = list(loop.coords)
    old_mortise_angle = 0
    distance = finger_size / 2
    j = 0
    print("joinery loop length", round(loop_length * 1000), "mm")
    for i, p in enumerate(coords):
        if i == 0:
            p_start = p

        if p != p_start:
            not_start = True
        else:
            not_start = False
        pd = loop.project(Point(p))

        if not_start:
            while distance <= pd:
                mortise_angle = angle(oldp, p)
                mortise_angle_difference = abs(mortise_angle -
                                               old_mortise_angle)
                mad = (1 + 6 * min(mortise_angle_difference, math.pi / 4) /
                       (math.pi / 4))  # factor for tolerance for the finger

                if base:
                    mortise(finger_size, finger_thick, finger_tolerance * mad,
                            distance, 0, 0)
                    simple.active_name("_base")
                else:
                    mortise_point = loop.interpolate(distance)
                    mortise(finger_size, finger_thick, finger_tolerance * mad,
                            mortise_point.x, mortise_point.y, mortise_angle)

                j += 1
                distance = j * 2 * finger_size + finger_size / 2
                old_mortise_angle = mortise_angle
        oldp = p
    if base:
        simple.join_multiple("_base")
        simple.active_name("base")
        simple.move(x=finger_size)
    else:
        simple.join_multiple("_mort")
        simple.active_name("mortise")
Esempio n. 5
0
def twist_separator_slot(length,
                         thickness,
                         finger_play=0.00005,
                         percentage=0.5):
    simple.add_rectangle(thickness + finger_play / 2, length, center_y=False)
    simple.move(y=((length * percentage - finger_play / 2) / 2))
    simple.duplicate()
    simple.mirrory()
    simple.join_multiple('simple_rectangle')
    simple.active_name('_separator_slot')
Esempio n. 6
0
def make_flex_pocket(length, height, finger_thick, finger_width, pocket_width):
    #   creates pockets pocket using mortise function for kerf bending
    dist = 3 * finger_width / 2
    while dist < length:
        mortise(height - 2 * finger_thick, pocket_width, 0, dist, 0,
                math.pi / 2)
        simple.active_name("_flex_pocket")
        dist += finger_width * 2

    simple.join_multiple("_flex_pocket")
    simple.active_name("flex_pocket")
Esempio n. 7
0
def interlock_twist_separator(length,
                              thickness,
                              amount,
                              spacing,
                              edge_distance,
                              finger_play=0.00005,
                              percentage=0.5,
                              start='rounded',
                              end='rounded'):
    amount -= 1
    base_width = 2 * edge_distance + spacing * amount + thickness
    simple.add_rectangle(base_width, length - finger_play * 2, center_x=False)
    simple.active_name('_base')
    twist_separator_slot(length, thickness, finger_play, percentage)
    while amount > 0:
        simple.duplicate(x=spacing)
        amount -= 1
    simple.join_multiple('_separator_slot')
    simple.move(x=edge_distance + thickness / 2)
    simple.difference('_', '_base')
    simple.active_name('twist_separator')
Esempio n. 8
0
def twist_line(length,
               thickness,
               finger_play,
               percentage,
               amount,
               distance,
               center=True):
    # Makes an amount of twist for the distance and  centers it
    spacing = distance / amount
    while amount > 0:
        position = spacing * amount
        interlock_twist(length,
                        thickness,
                        finger_play,
                        percentage=percentage,
                        cx=position)
        print('twistline', amount, distance, position)
        amount -= 1

    simple.join_multiple('_groove')
    simple.active_name('twist_line')
    if center:
        simple.move(x=(-distance - spacing) / 2)
Esempio n. 9
0
def horizontal_finger(length, thickness, finger_play, amount, center=True):
    #   creates _wfa counterpart _wfb
    #   _wfa is centered at 0,0
    #   _wfb is _wfa offset by one length
    #   takes in the
    #   length = length of the mortise
    #   thickness = thickness of the material
    #   fingerplay = tolerance in length of the finger for smooth fit
    if center:
        for i in range(amount):
            if i == 0:
                mortise(length, thickness, finger_play, 0, thickness / 2)
                simple.active_name("_width_finger")
            else:
                mortise(length, thickness, finger_play, i * 2 * length,
                        thickness / 2)
                simple.active_name("_width_finger")
                mortise(length, thickness, finger_play, -i * 2 * length,
                        thickness / 2)
                simple.active_name("_width_finger")
    else:
        for i in range(amount):
            mortise(length, thickness, finger_play,
                    length / 2 + 2 * i * length, 0)
            simple.active_name("_width_finger")

    simple.join_multiple("_width_finger")

    simple.active_name("_wfa")
    bpy.ops.object.duplicate_move(
        OBJECT_OT_duplicate={
            "linked": False,
            "mode": 'TRANSLATION'
        },
        TRANSFORM_OT_translate={"value": (length, 0.0, 0.0)})
    simple.active_name("_wfb")
Esempio n. 10
0
def open_curve(line, thick, diameter, tolerance, amount=0, stem=1, twist=False, t_neck=0.5, t_thick=0.01,
               twist_amount=1, which='MF', twist_keep=False):
    # puts puzzle connectors at the end of an open curve
    # optionally puts twist lock connectors at the puzzle connection
    # optionally puts twist lock connectors along the open curve
    # line = shapely linestring
    # thick = thickness of the bar
    # diameter = diameter of the tool for joint creation
    # tolerance = Tolerance in the joint
    # amount = amount of fingers in the joint 0 means auto generate
    # stem = amount of radius the stem or neck of the joint will have
    # twist = twist lock addition
    # twist_amount = twist amount distributed on the curve not counting the joint twist locks
    # tneck = percentage the twist neck will have compared to thick
    # tthick = thicknest of the twist material
    # Which M,F, MF, MM, FF

    coords = list(line.coords)

    start_angle = joinery.angle(coords[0], coords[1]) + math.pi/2
    end_angle = joinery.angle(coords[-1], coords[-2]) + math.pi/2
    p_start = coords[0]
    p_end = coords[-1]

    print('start angle', start_angle)
    print('end angle', end_angle)

    bpy.ops.curve.simple(align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), Simple_Type='Rectangle',
                         Simple_width=thick*2, Simple_length=thick * 2, use_cyclic_u=True, edit_mode=False, shape='3D')
    simple.active_name('tmprect')
    simple.move(y=thick)
    simple.duplicate()
    simple.rotate(start_angle)
    simple.move(x=p_start[0], y=p_start[1])
    simple.make_active('tmprect')
    simple.rotate(end_angle)
    simple.move(x=p_end[0], y=p_end[1])
    simple.union('tmprect')
    dilated = line.buffer(thick/2)  # expand shapely object to thickness
    utils.shapelyToCurve('tmp_curve', dilated, 0.0)
    simple.difference('tmp', 'tmp_curve')   # truncate curve at both ends with the rectangles

    fingers(diameter, tolerance, amount, stem=stem)
    simple.make_active('fingers')
    simple.rotate(end_angle)
    simple.move(x=p_end[0], y=p_end[1])
    simple.active_name('tmp_fingers')
    simple.union('tmp_')
    simple.active_name('tmp_curve')
    twistm('tmp_curve', thick, diameter, tolerance, twist, t_neck, t_thick, end_angle, x=p_end[0], y=p_end[1],
           twist_keep=twist_keep)

    twistf('receptacle', thick, diameter, tolerance, twist, t_neck, t_thick, twist_keep=twist_keep)
    simple.rename('receptacle', 'tmp')
    simple.rotate(start_angle+math.pi)
    simple.move(x=p_start[0], y=p_start[1])
    simple.difference('tmp', 'tmp_curve')
    if twist_keep:
        simple.make_active('twist_keep_f')
        simple.rotate(start_angle + math.pi)
        simple.move(x=p_start[0], y=p_start[1])

    if twist_amount > 0 and twist:
        twist_start = line.length / (twist_amount+1)
        joinery.distributed_interlock(line, line.length, thick, t_thick, tolerance, twist_amount,
                                      tangent=math.pi/2, fixed_angle=0, start=twist_start, end=twist_start,
                                      closed=False, type='TWIST', twist_percentage=t_neck)
        if twist_keep:
            simple.duplicate()
            simple.active_name('twist_keep')
            simple.join_multiple('twist_keep')
            simple.make_active('interlock')

        simple.active_name('tmp_twist')
        simple.difference('tmp', 'tmp_curve')
        simple.active_name('puzzle_curve')
Esempio n. 11
0
def distributed_interlock(loop,
                          loop_length,
                          finger_depth,
                          finger_thick,
                          finger_tolerance,
                          finger_amount,
                          tangent=0,
                          fixed_angle=0,
                          start=0.01,
                          end=0.01,
                          closed=True,
                          type='GROOVE',
                          twist_percentage=0.5):
    #   distributes interlocking joints of a fixed amount
    #   dynamically changes the finger tolerance with the angle differences
    #   loop = takes in a shapely shape
    #   finger_size = size of the mortise
    #   finger_thick = thickness of the material
    #   finger_tolerance = minimum finger tolerance
    #   twist_percentage = portion of twist finger which is the stem
    coords = list(loop.coords)
    print(closed)
    if not closed:
        spacing = (loop_length - start - end) / (finger_amount - 1)
        distance = start
        end_distance = loop_length - end
    else:
        spacing = loop_length / finger_amount
        distance = 0
        end_distance = loop_length

    j = 0
    print("joinery loop length", round(loop_length * 1000), "mm")
    print("distance between joints", round(spacing * 1000), "mm")

    for i, p in enumerate(coords):
        if i == 0:
            p_start = p

        if p != p_start:
            not_start = True
        else:
            not_start = False
        pd = loop.project(Point(p))

        if not_start:
            while distance <= pd and end_distance >= distance:
                if fixed_angle == 0:
                    groove_angle = angle(oldp, p) + math.pi / 2 + tangent
                else:
                    groove_angle = fixed_angle

                groove_point = loop.interpolate(distance)

                print(j, "groove_angle", round(180 * groove_angle / math.pi),
                      "distance", round(distance * 1000), "mm")
                single_interlock(finger_depth,
                                 finger_thick,
                                 finger_tolerance,
                                 groove_point.x,
                                 groove_point.y,
                                 groove_angle,
                                 type,
                                 twist_percentage=twist_percentage)

                j += 1
                distance = j * spacing + start
        oldp = p

    simple.join_multiple("_groove")
    simple.active_name("interlock")
Esempio n. 12
0
def variable_finger(loop,
                    loop_length,
                    min_finger,
                    finger_size,
                    finger_thick,
                    finger_tolerance,
                    adaptive,
                    base=False,
                    double_adaptive=False):
    #   distributes mortises of a fixed distance
    #   dynamically changes the finger tolerance with the angle differences
    #   loop = takes in a shapely shape
    #   finger_size = size of the mortise
    #   finger_thick = thickness of the material
    #   finger_tolerance = minimum finger tolerance
    #   adaptive = angle threshold to reduce finger size

    coords = list(loop.coords)
    old_mortise_angle = 0
    distance = min_finger / 2
    finger_sz = min_finger
    oldfinger_sz = min_finger
    hpos = []  # hpos is the horizontal positions of the middle of the mortise
    # slope_array(loop)
    print("joinery loop length", round(loop_length * 1000), "mm")
    for i, p in enumerate(coords):
        if i == 0:
            p_start = p

        if p != p_start:
            not_start = True
        else:
            not_start = False
        pd = loop.project(Point(p))

        if not_start:
            while distance <= pd:
                mortise_angle = angle(oldp, p)
                mortise_angle_difference = abs(mortise_angle -
                                               old_mortise_angle)
                mad = (1 + 6 * min(mortise_angle_difference, math.pi / 4) /
                       (math.pi / 4))  # factor for tolerance for the finger
                distance += mad * finger_tolerance  # move finger by the factor mad greater with larger angle difference
                mortise_point = loop.interpolate(distance)
                if mad > 2 and double_adaptive:
                    hpos.append(distance)  # saves the mortise center

                hpos.append(distance + finger_sz)  # saves the mortise center
                if base:
                    mortise(finger_sz, finger_thick, finger_tolerance * mad,
                            distance + finger_sz, 0, 0)
                    simple.active_name("_base")
                else:
                    mortise(finger_sz, finger_thick, finger_tolerance * mad,
                            mortise_point.x, mortise_point.y, mortise_angle)
                    if i == 1:
                        #  put a mesh cylinder at the first coordinates to indicate start
                        simple.remove_multiple("start_here")
                        bpy.ops.mesh.primitive_cylinder_add(
                            radius=finger_thick / 2,
                            depth=0.025,
                            enter_editmode=False,
                            align='WORLD',
                            location=(mortise_point.x, mortise_point.y, 0),
                            scale=(1, 1, 1))
                        simple.active_name("start_here_mortise")

                old_distance = distance
                old_mortise_point = mortise_point
                finger_sz = finger_size
                next_angle_difference = math.pi

                #   adaptive finger length start
                while finger_sz > min_finger and next_angle_difference > adaptive:
                    finger_sz *= 0.95  # reduce the size of finger by a percentage... the closer to 1.0, the slower
                    distance = old_distance + 3 * oldfinger_sz / 2 + finger_sz / 2
                    mortise_point = loop.interpolate(
                        distance)  # get the next mortise point
                    next_mortise_angle = angle(
                        (old_mortise_point.x, old_mortise_point.y),
                        (mortise_point.x,
                         mortise_point.y))  # calculate next angle
                    next_angle_difference = abs(next_mortise_angle -
                                                mortise_angle)

                oldfinger_sz = finger_sz
                old_mortise_angle = mortise_angle
        oldp = p
    if base:
        simple.join_multiple("_base")
        simple.active_name("base")
    else:
        print("placeholder")
        simple.join_multiple("_mort")
        simple.active_name("variable_mortise")
    return hpos
Esempio n. 13
0
def gear(mm_per_tooth=0.003,
         number_of_teeth=5,
         hole_diameter=0.003175,
         pressure_angle=0.3488,
         clearance=0.0,
         backlash=0.0,
         rim_size=0.0005,
         hub_diameter=0.006,
         spokes=4):
    simple.deselect()
    pi = math.pi
    p = mm_per_tooth * number_of_teeth / pi / 2  # radius of pitch circle
    c = p + mm_per_tooth / pi - clearance  # radius of outer circle
    b = p * math.cos(pressure_angle)  # radius of base circle
    r = p - (c - p) - clearance  # radius of root circle
    t = mm_per_tooth / 2 - backlash / 2  # tooth thickness at pitch circle
    k = -gear_iang(
        b, p
    ) - t / 2 / p  # angle to where involute meets base circle on each side of tooth
    shapely_gear = Polygon([(0, 0),
                            gear_polar(r,
                                       k if r < b else -pi / number_of_teeth),
                            gear_q7(0, r, b, c, k, 1),
                            gear_q7(0.1, r, b, c, k, 1),
                            gear_q7(0.2, r, b, c, k, 1),
                            gear_q7(0.3, r, b, c, k, 1),
                            gear_q7(0.4, r, b, c, k, 1),
                            gear_q7(0.5, r, b, c, k, 1),
                            gear_q7(0.6, r, b, c, k, 1),
                            gear_q7(0.7, r, b, c, k, 1),
                            gear_q7(0.8, r, b, c, k, 1),
                            gear_q7(0.9, r, b, c, k, 1),
                            gear_q7(1.0, r, b, c, k, 1),
                            gear_q7(1.0, r, b, c, k, -1),
                            gear_q7(0.9, r, b, c, k, -1),
                            gear_q7(0.8, r, b, c, k, -1),
                            gear_q7(0.7, r, b, c, k, -1),
                            gear_q7(0.6, r, b, c, k, -1),
                            gear_q7(0.5, r, b, c, k, -1),
                            gear_q7(0.4, r, b, c, k, -1),
                            gear_q7(0.3, r, b, c, k, -1),
                            gear_q7(0.2, r, b, c, k, -1),
                            gear_q7(0.1, r, b, c, k, -1),
                            gear_q7(0.0, r, b, c, k, -1),
                            gear_polar(r,
                                       -k if r < b else pi / number_of_teeth)])
    utils.shapelyToCurve('tooth', shapely_gear, 0.0)
    i = number_of_teeth
    while i > 1:
        simple.duplicate()
        simple.rotate(2 * math.pi / number_of_teeth)
        i -= 1
    simple.join_multiple('tooth')
    simple.active_name('_teeth')

    bpy.ops.curve.simple(align='WORLD',
                         location=(0, 0, 0),
                         rotation=(0, 0, 0),
                         Simple_Type='Circle',
                         Simple_radius=r,
                         shape='3D',
                         use_cyclic_u=True,
                         edit_mode=False)
    simple.active_name('_hub')
    simple.union('_')
    simple.active_name('_gear')
    simple.remove_doubles()

    if spokes > 0:
        bpy.ops.curve.simple(align='WORLD',
                             location=(0, 0, 0),
                             rotation=(0, 0, 0),
                             Simple_Type='Circle',
                             Simple_radius=r - rim_size,
                             shape='3D',
                             use_cyclic_u=True,
                             edit_mode=False)
        simple.active_name('_hole')
        simple.difference('_', '_gear')
        bpy.ops.curve.simple(align='WORLD',
                             location=(0, 0, 0),
                             rotation=(0, 0, 0),
                             Simple_Type='Circle',
                             Simple_radius=hub_diameter / 2,
                             shape='3D',
                             use_cyclic_u=True,
                             edit_mode=False)
        simple.active_name('_hub')
        bpy.ops.curve.simple(align='WORLD',
                             location=(0, 0, 0),
                             rotation=(0, 0, 0),
                             Simple_Type='Circle',
                             Simple_radius=hole_diameter / 2,
                             shape='3D',
                             use_cyclic_u=True,
                             edit_mode=False)
        simple.active_name('_hub_hole')
        simple.difference('_hub', '_hub')

        simple.join_multiple('_')

        simple.add_rectangle(
            r - rim_size -
            ((hub_diameter - hole_diameter) / 4 + hole_diameter / 2),
            hub_diameter / 2,
            center_x=False)
        simple.move(x=(hub_diameter - hole_diameter) / 4 + hole_diameter / 2)
        simple.active_name('_spoke')

        angle = 2 * pi / spokes
        while spokes > 0:
            simple.duplicate()
            simple.rotate(angle)
            spokes -= 1
        simple.union('_spoke')
        simple.remove_doubles()
        simple.union('_')
    else:
        bpy.ops.curve.simple(align='WORLD',
                             location=(0, 0, 0),
                             rotation=(0, 0, 0),
                             Simple_Type='Circle',
                             Simple_radius=hole_diameter,
                             shape='3D',
                             use_cyclic_u=True,
                             edit_mode=False)
        simple.active_name('_hole')
        simple.difference('_', '_gear')

    name = 'gear-' + str(round(mm_per_tooth * 1000, 1))
    name += 'mm-pitch-' + str(number_of_teeth)
    name += 'teeth-PA-' + str(round(math.degrees(pressure_angle), 1))
    simple.active_name(name)