Пример #1
0
def assembly():
    axle = sp.color('red')(
        round_bar.volume(
            diameter=axle_diameter, length=axle_length, center=True
        )
    )

    sprocket_assy = spu.up(sprocket_pos)(
        sp.color('green')(sp.rotate((180, 0, 0))(drive_sprocket.assembly()))
    )

    brake_disc_assy = spu.down(brake_disc_pos)(
        sp.color('blue')(brake_disc.assembly())
    )

    wheels = [
        sp.rotate([0, a, 0])(
            spu.left(wheel_centre_distance / 2.)(
                sp.color('cyan')(wheel.assembly())
            )
        ) for a in [0, 180]
    ]

    return sp.union()(
        sp.rotate([0, 90,
                   0])(sp.union()(
                       axle,
                       sprocket_assy,
                       brake_disc_assy,
                   )),
        wheels,
    )
Пример #2
0
def model_right():
    shape = sl.union()(
        key_holes(),
        connectors(),
        thumb(),
        thumb_connectors(),
    )

    s2 = sl.union()(
        case_walls(),
        screw_insert_outers(),
        teensy_holder(),
        usb_holder(),
    )

    s2 = sl.difference()(s2, rj9_space(), usb_holder_hole(),
                         screw_insert_holes())

    shape = sl.union()(
        shape,
        s2,
        rj9_holder(),
        wire_posts(),
    )

    shape -= sl.translate([0, 0, -20])(sl.cube([350, 350, 40], center=True))
    return shape
Пример #3
0
    def get_shape(self, with_verts=False):
        if with_verts:
            shape = sl.union()(self.shape,
                               self.vertices_shape(),
                               self.unrotated_verts_shape(),
                               self.origin_marker(),
                               self.unrotated_origin_marker())
            if self.cap is not None:
                return sl.union()(shape, self.cap)
            return shape

        return self.shape
Пример #4
0
def plane_make_part3D(self, thepart, pconfig):
	self.generate_part3D(thepart, pconfig)
#	for cutout in thepart.cutouts3D:
#		for c in cutout:
#			thepart.border3D = thepart.border3D - c
	subparts = []
	for sp in thepart.parts:
		if hasattr(sp, 'subpart') and sp.subpart:
			self.make_part3D(sp, pconfig)
			if hasattr(sp, 'border3D'):
				subparts.append(sp.border3D)
	if len(subparts):
		if hasattr(thepart, 'border3D'):
			thepart.border3D=solid.union()(thepart.border3D,*subparts)
		else:
			thepart.border3D=solid.union()(*subparts)
	if not hasattr(thepart, 'border3D'):
		return False
	cutouts = [thepart.border3D]
	for cutout in thepart.cutouts3D:
		for c in cutout:
			cutouts.append(c)

	thepart.border3D = solid.difference()(*cutouts)
	# 3D transformations can only be applied to parts, so we can just go up the tree
	p = thepart
	c=0
	print p
	while(p and type(p) is not Plane):# and (c==0 or not p.renderable() )):
		p.rotations_to_3D()
		if hasattr(p, 'transform') and p.transform is not None and p.transform is not False:
			print p.transform
			if 'matrix3D' in p.transform:
				if type(p.transform['matrix3D'][0]) is list or type(p.transform['matrix3D'][0]) is Vec:
                                        thepart.border3D=solid.translate([-p.transform['matrix3D'][0][0], -p.transform['matrix3D'][0][1],-p.transform['matrix3D'][0][2]])(thepart.border3D)
					thepart.border3D=solid.multmatrix(m=p.transform['matrix3D'][1])(thepart.border3D)
					thepart.border3D=solid.translate([p.transform['matrix3D'][0][0], p.transform['matrix3D'][0][1],p.transform['matrix3D'][0][2]])(thepart.border3D)
				else:
					thepart.border3D=solid.multmatrix(m=p.transform['matrix3D'])(thepart.border3D)

			if 'rotate3D' in p.transform: 
				if type(p.transform['rotate3D'][0]) is list or type(p.transform['rotate3D'][0]) is Vec:
					thepart.border3D=solid.translate([-p.transform['rotate3D'][0][0], -p.transform['rotate3D'][0][1],-p.transform['rotate3D'][0][2]])(thepart.border3D)
					thepart.border3D=solid.rotate([p.transform['rotate3D'][1][0], p.transform['rotate3D'][1][1],p.transform['rotate3D'][1][2] ])(thepart.border3D)
					thepart.border3D=solid.translate([p.transform['rotate3D'][0][0], p.transform['rotate3D'][0][1],p.transform['rotate3D'][0][2]])(thepart.border3D)
				else:
					thepart.border3D=solid.rotate([p.transform['rotate3D'][0], p.transform['rotate3D'][1],p.transform['rotate3D'][2] ])(thepart.border3D)
			if 'translate3D' in p.transform:
				thepart.border3D=solid.translate([p.transform['translate3D'][0], p.transform['translate3D'][1],p.transform['translate3D'][2] ])(thepart.border3D)
		c+=1
		p=p.parent
Пример #5
0
def plane_make_part3D(self, thepart, pconfig):
        self.generate_part3D(thepart, pconfig)
#	for cutout in thepart.cutouts3D:
#		for c in cutout:
#			thepart.border3D = thepart.border3D - c
        subparts = []
        for sp in thepart.parts:
                if hasattr(sp, 'subpart') and sp.subpart:
                        self.make_part3D(sp, pconfig)
                        if hasattr(sp, 'border3D'):
                                subparts.append(sp.border3D)
        if len(subparts):
                if hasattr(thepart, 'border3D'):
                        thepart.border3D=solid.union()(thepart.border3D,*subparts)
                else:
                        thepart.border3D=solid.union()(*subparts)
        if not hasattr(thepart, 'border3D'):
                return False
        cutouts = [thepart.border3D]
        for cutout in thepart.cutouts3D:
                for c in cutout:
                        cutouts.append(c)

        thepart.border3D = solid.difference()(*cutouts)
        # 3D transformations can only be applied to parts, so we can just go up the tree
        p = thepart
        c=0
        while(p and type(p) is not Plane):# and (c==0 or not p.renderable() )):
                p.rotations_to_3D()
                if hasattr(p, 'transform') and p.transform is not None and p.transform is not False:
                        if 'matrix3D' in p.transform:
                                if type(p.transform['matrix3D'][0]) is list or type(p.transform['matrix3D'][0]) is Vec:
                                        thepart.border3D=solid.translate([-p.transform['matrix3D'][0][0], -p.transform['matrix3D'][0][1],-p.transform['matrix3D'][0][2]])(thepart.border3D)
                                        thepart.border3D=solid.multmatrix(m=p.transform['matrix3D'][1])(thepart.border3D)
                                        thepart.border3D=solid.translate([p.transform['matrix3D'][0][0], p.transform['matrix3D'][0][1],p.transform['matrix3D'][0][2]])(thepart.border3D)
                                else:
                                        thepart.border3D=solid.multmatrix(m=p.transform['matrix3D'])(thepart.border3D)

                        if 'rotate3D' in p.transform: 
                                if type(p.transform['rotate3D'][0]) is list or type(p.transform['rotate3D'][0]) is Vec:
                                        thepart.border3D=solid.translate([-p.transform['rotate3D'][0][0], -p.transform['rotate3D'][0][1],-p.transform['rotate3D'][0][2]])(thepart.border3D)
                                        thepart.border3D=solid.rotate([p.transform['rotate3D'][1][0], p.transform['rotate3D'][1][1],p.transform['rotate3D'][1][2] ])(thepart.border3D)
                                        thepart.border3D=solid.translate([p.transform['rotate3D'][0][0], p.transform['rotate3D'][0][1],p.transform['rotate3D'][0][2]])(thepart.border3D)
                                else:
                                        thepart.border3D=solid.rotate([p.transform['rotate3D'][0], p.transform['rotate3D'][1],p.transform['rotate3D'][2] ])(thepart.border3D)
                        if 'translate3D' in p.transform:
                                thepart.border3D=solid.translate([p.transform['translate3D'][0], p.transform['translate3D'][1],p.transform['translate3D'][2] ])(thepart.border3D)
                c+=1
                p=p.parent
Пример #6
0
def create_model(data, rows, columns):
    hexes = to_base(int.from_bytes(data, 'big'), 720)
    assert len(hexes) == rows * columns

    sts = []
    for row in range(rows):
        for col in range(columns):
            order = permute.permute([1, 2, 3, 4, 5, 6], hexes[row * 9 + col])

            heights = [1 + 1.5 * i / len(order) for i in order]
            st = stump(heights)

            xdiff = 1.5 * col
            xdiff *= 1.2
            ydiff = (-3**0.5) * row - (3**0.5 / 2) * col
            ydiff *= 1.2
            st = solid.translate([xdiff, ydiff, 0])(st)

            sts.append(st)

    base = solid.translate([-3.4, -3.2, 0])(solid.rotate([0, 0, -30])(
        solid.scale([22, 6.5, 0.3])(solid.cube(1))))

    x, y = 0.5, (3**0.5 / 2) / 2
    marker = solid.translate([-1.5, -2.5, 0])(
        solid.polyhedron(
            points=[
                # bottom
                (-x, -y, 0),
                (x, -y, 0),
                (0, y, 0),
                # top
                (-x, -y, 1),
                (x, -y, 1),
                (0, y, 1)
            ],
            faces=[
                # bottom
                (0, 1, 2),
                # top
                (5, 4, 3),
                # sides
                (0, 3, 4, 1),
                (1, 4, 5, 2),
                (2, 5, 3, 0)
            ]))

    return solid.union()([base, solid.union()(sts), marker])
Пример #7
0
def create_cutouts(solder_paste, increase_hole_size_by=0.0):
    solder_paste.to_metric()

    cutout_shapes = []
    cutout_lines = []

    apertures = {}
    current_aperture = None
    current_x = None
    current_y = None
    for statement in solder_paste.statements:
        if statement.type == 'PARAM' and statement.param == 'AD':  # define aperture
            apertures[statement.d] = {
                'shape': statement.shape,
                'modifiers': statement.modifiers
            }
        elif statement.type == 'APERTURE':
            current_aperture = statement.d
        elif statement.type == 'COORD' and statement.op == 'D3':  # flash object coordinates
            if not current_aperture:
                raise Exception("No aperture set on flash object coordinates!")

            aperture = apertures[current_aperture]
            current_x = statement.x if statement.x is not None else current_x
            current_y = statement.y if statement.y is not None else current_y
            if aperture['shape'] == 'C':  # circle
                cutout_shapes.append(
                    primitive_to_shape(
                        primitives.Circle(diameter=aperture['modifiers'][0][0],
                                          position=[current_x, current_y])))
            elif aperture['shape'] == 'R':  # rectangle
                width, height = aperture['modifiers'][0]
                cutout_shapes.append(
                    primitive_to_shape(
                        primitives.Rectangle(
                            position=[current_x, current_y],
                            width=width,
                            height=height,
                        )))
            else:
                raise NotImplementedError(
                    "Only circular and rectangular flash objects are supported!"
                )

    for p in solder_paste.primitives:
        shape = primitive_to_shape(p)
        if len(shape) > 2:
            cutout_shapes.append(shape)
        else:
            cutout_lines.append(shape)

    # If the cutouts contain lines we try to first join them together into shapes
    cutout_shapes += lines_to_shapes(cutout_lines)
    polygons = []
    for shape in cutout_shapes:
        if increase_hole_size_by and len(shape) > 2:
            shape = offset_shape(shape, increase_hole_size_by)
        polygons.append(polygon([[x, y] for x, y in shape]))

    return union()(*polygons)
Пример #8
0
def connectors():
    hulls = []
    for column in range(ncols - 1):
        for row in range(lastrow):  # need to consider last_row?
            # for row in range(nrows):  # need to consider last_row?
            places = []
            places.append(key_place(web_post_tl(), column + 1, row))
            places.append(key_place(web_post_tr(), column, row))
            places.append(key_place(web_post_bl(), column + 1, row))
            places.append(key_place(web_post_br(), column, row))
            hulls.append(triangle_hulls(places))

    for column in range(ncols):
        # for row in range(nrows-1):
        for row in range(cornerrow):
            places = []
            places.append(key_place(web_post_bl(), column, row))
            places.append(key_place(web_post_br(), column, row))
            places.append(key_place(web_post_tl(), column, row + 1))
            places.append(key_place(web_post_tr(), column, row + 1))
            hulls.append(triangle_hulls(places))

    for column in range(ncols - 1):
        # for row in range(nrows-1):  # need to consider last_row?
        for row in range(cornerrow):  # need to consider last_row?
            places = []
            places.append(key_place(web_post_br(), column, row))
            places.append(key_place(web_post_tr(), column, row + 1))
            places.append(key_place(web_post_bl(), column + 1, row))
            places.append(key_place(web_post_tl(), column + 1, row + 1))
            hulls.append(triangle_hulls(places))

    return sl.union()(*hulls)
Пример #9
0
def thumb_1x_layout(shape):
    return sl.union()(
        thumb_mr_place(shape),
        thumb_ml_place(shape),
        thumb_br_place(shape),
        thumb_bl_place(shape),
    )
Пример #10
0
def teensy_holder():
    s1 = sl.cube([3, teensy_holder_length, 6 + teensy_width], center=True)
    s1 = sl.translate([1.5, teensy_holder_offset, 0])(s1)

    s2 = sl.cube([teensy_pcb_thickness, teensy_holder_length, 3], center=True)
    s2 = sl.translate([
        (teensy_pcb_thickness / 2) + 3,
        teensy_holder_offset,
        -1.5 - (teensy_width / 2),
    ])(s2)

    s3 = sl.cube([teensy_pcb_thickness, teensy_holder_top_length, 3],
                 center=True)
    s3 = sl.translate([
        (teensy_pcb_thickness / 2) + 3,
        teensy_holder_top_offset,
        1.5 + (teensy_width / 2),
    ])(s3)

    s4 = sl.cube([4, teensy_holder_top_length, 4], center=True)
    s4 = sl.translate([
        teensy_pcb_thickness + 5, teensy_holder_top_offset,
        1 + (teensy_width / 2)
    ])(s4)

    shape = sl.union()(s1, s2, s3, s4)

    shape = sl.translate([-teensy_holder_width, 0, 0])(shape)
    shape = sl.translate([-1.4, 0, 0])(shape)
    shape = sl.translate(
        [teensy_top_xy[0], teensy_top_xy[1] - 1,
         (6 + teensy_width) / 2])(shape)

    return shape
Пример #11
0
def assembly():
    return sp.union()(
        sp.color('red')(spu.left(100.)(wheel.volume())),
        sp.color('green')(left_stub_axle.volume()),
        sp.color('blue')(spu.left(58.)(sp.rotate(
            (0., -90., 0.))(wheel_bushing.volume()))),
    )
Пример #12
0
def flat_cap(x, y, z, r, recess=0):
    """flat_cap
    x, y, z cap dimensions
    r (int): radius for rounded edges
    recess: decimal, percent of cap to remove
    """

    cap = rounded_cube(x, y, z, r)

    if recess > 0:
        if recess < 1:
            insert = rounded_cube(x * recess,
                                  y * recess, (z * recess) - 0.5,
                                  r,
                                  center=True)

            cap = s.difference()(cap,
                                 s.translate([0, 0,
                                              z - (z * recess) + 0.5])(insert))

        else:
            raise ValueError(f"recess should be a decimal between 0 and 1")

    out = s.union()(cap, mx_post(6, z / 2))
    return out
Пример #13
0
def tetrahedron():
    """ Creates a ball-and-stick model of a geodesic sphere based off of an tetrahedron,
    highlighting vertices of valence 3 """

    (vs, es, fs) = geo.sphere(v=3, base=geo.tetrahedron_vertices)
    vms = geo.vertex_matrices(vs)
    ems = geo.edge_matrices(es, vs)
    els = geo.edge_lengths(es, vs)
    ves = geo.vertex_edges(es)

    highlight_valence = 3

    def shape_at_vertex(m, ve):
        shape = solid.sphere(r=0.05)
        if len(ve) == highlight_valence:
            shape = solid.color("red")(shape)
        return solid.multmatrix(m)(shape)

    def shape_at_edge(m, el, e):
        shape = solid.cylinder(r1=0.03, r2=0.03, h=el, center=True)
        if any(len(ves[i]) == highlight_valence for i in e):
            shape = solid.color("red")(shape)

        return solid.multmatrix(m)(solid.utils.rot_z_to_right(shape))

    shape = solid.union()(
        *[shape_at_vertex(m, ve) for m, ve in zip(vms, ves)],
        *[shape_at_edge(m, el, e) for m, el, e in zip(ems, els, es)])

    return shape
Пример #14
0
def spaceship_earth():
    """ Creates a model of EPCOT's spaceship earth """

    (vs, es, fs) = geo.sphere(v=8)
    fms = geo.face_matrices(fs, vs)
    fts = geo.face_triangles_2d(fs, vs, fms)

    def shape_at_face(m, ft):
        center = np.array([0, 0])
        panel1 = np.vstack((ft[0], ft[1], center))
        panel2 = np.vstack((ft[1], ft[2], center))
        panel3 = np.vstack((ft[2], ft[0], center))

        panel_angle = 20

        def panel_shape(panel_tri):
            edge_midpoint = 0.5 * (panel_tri[0] + panel_tri[1])
            rotation_vector = panel_tri[1] - panel_tri[0]

            transform = lambda x: solid.translate(
                edge_midpoint)(solid.rotate(a=panel_angle, v=rotation_vector)
                               (solid.translate(-edge_midpoint)(x)))

            return transform(
                solid.linear_extrude(0.01)(solid.polygon(panel_tri * 0.9)))

        return solid.multmatrix(m)(
            solid.union()(*[panel_shape(p) for p in (panel1, panel2, panel3)]))

    inner_radius = np.mean(np.linalg.norm(np.array(fms)[:, 0:3, 3], axis=1))

    return solid.union()(solid.sphere(r=inner_radius, segments=FN * 4),
                         *[shape_at_face(m, ft) for m, ft in zip(fms, fts)])
Пример #15
0
def assembly():
    column = tube.volume(diameter=column_diameter, wall_thickness=2., length=column_length)

    return sp.union()(
        spu.up(column_length)(
            spu.up(wheel.plate_thickness / 2.)(
                sp.color('red')(wheel.volume()),
                spu.up(wheel.plate_thickness / 2.)(
                    sp.color('green')(instrument_panel.assembly())
                ),
                sp.translate((150, 80))(
                    sp.rotate((0., 60., 0.))(
                        sp.color('blue')(throttle.assembly())
                    )
                ),
            ),
            sp.rotate((0, 180, 0))(sp.color('cyan')(wheel_mount.volume())),
        ),
        sp.color('magenta')(column),
        spu.up(440.)(sp.color('purple')(column_mount.upper.assembly())),
        spu.up(60.)(sp.color('grey')(column_mount.lower.assembly())),
        sp.rotate((0, 0, 0))(
            sp.color('orange')(arm_mount.volume()),
            sp.color('pink')(spu.down(arm.thickness)(arm.volume())),
        ),
    )
Пример #16
0
def volume():
    base = spu.up(base_height / 2.)(
        sp.cube([width, base_length, base_height], center=True)
    )

    mounting_holes = spu.down(1)(
        place_at_centres(
            [0, mounting_hole_centres],
            sp.cylinder(d=mounting_hole_diameter, h=base_height + 2)
        )
    )

    base -= mounting_holes

    bearing = spu.up(shaft_height)(
        sp.rotate([0, 90, 0])(
            sp.cylinder(d=60, h=width, center=True) -
            sp.cylinder(d=shaft_diameter, h=width + 1, center=True)
        )
    )

    return sp.union()(
        base,
        bearing,
    )
Пример #17
0
def single_plate(cylinder_segments=100):
    top_wall = sl.cube([keyswitch_width + 3, 1.5, plate_thickness],
                       center=True)
    top_wall = sl.translate(
        (0, (1.5 / 2) + (keyswitch_height / 2), plate_thickness / 2))(top_wall)

    left_wall = sl.cube([1.5, keyswitch_height + 3, plate_thickness],
                        center=True)
    left_wall = sl.translate(
        ((1.5 / 2) + (keyswitch_width / 2), 0, plate_thickness / 2))(left_wall)

    side_nub = sl.cylinder(1, 2.75, segments=cylinder_segments, center=True)
    side_nub = sl.rotate(rad2deg(pi / 2), [1, 0, 0])(side_nub)
    side_nub = sl.translate((keyswitch_width / 2, 0, 1))(side_nub)
    nub_cube = sl.cube([1.5, 2.75, plate_thickness], center=True)
    nub_cube = sl.translate(
        ((1.5 / 2) + (keyswitch_width / 2), 0, plate_thickness / 2))(nub_cube)

    side_nub = sl.hull()(side_nub, nub_cube)

    plate_half1 = top_wall + left_wall + side_nub
    plate_half2 = plate_half1
    plate_half2 = sl.mirror([0, 1, 0])(plate_half2)
    plate_half2 = sl.mirror([1, 0, 0])(plate_half2)

    plate = plate_half1 + plate_half2

    if plate_file is not None:
        socket = sl.import_(plate_file)
        socket = sl.translate([0, 0, plate_offset])(socket)

        plate = sl.union()(plate, socket)

    return plate
Пример #18
0
def platform(width, length, height):
    foot = end(width)
    head = translate((0, length, 0))(mirror((0, 1, 0))(foot))
    slats = union()(
        [translate((0, y, 0))(slat(width)) for y in range(0, 70, 7)])
    return (platform_color(head) + platform_color(foot) +
            platform_color(translate((0, 6.5, 0))(slats)))
Пример #19
0
def single_slice(index):
    for slice_num, (lower, upper) in enumerate(slice_parameters()):
        if slice_num == index:
            return solid.translate([0, 0, upper - lower])(
                solid.rotate([0, 180, 0])(
                    solid.union()(*produce_slice(lower, upper))
                    ))
    raise Exception("Non-existent slice %i, max: %i!" % (index, slice_num))
Пример #20
0
def full_cone():
    cylinders = []
    for slice_num, (lower, upper) in enumerate(slice_parameters()):
        cylinders.extend(produce_slice(lower, upper, mdf_strength * slice_num))

    return solid.translate([0, 0, cone_length])(
        solid.rotate([0, 180, 0])(
            solid.union()(*cylinders)
            )
        )
Пример #21
0
def slice_sim(slices, t_m=3.0):
    """ Returns simulation of assembled slice-formed solid.

    Args:
      slices ([PolyLine]): list of PolyLines to simulate.
      t_m (float): material thickness

    Returns:
      A PolyMesh representing the assembled slices.

    """
    # assume stacked in the z dimension
    axis = np.array([0, 0, 1])
    slice_solids = []
    for (i, slice) in enumerate(slices):
        translation = list(t_m * axis * i)
        slice_solid = sl.linear_extrude(t_m)(slice.get_generator())
        positioned_solid = sl.translate(translation)(slice_solid)
        slice_solids.append(positioned_solid)
    return PolyMesh(generator=sl.union()(slice_solids))
Пример #22
0
def create_cutouts(solder_paste, increase_hole_size_by=0.0):
    solder_paste.to_metric()

    cutout_shapes = []
    cutout_lines = []

    for p in solder_paste.primitives:
        shape = primitive_to_shape(p)
        if len(shape) > 2:
            cutout_shapes.append(shape)
        else:
            cutout_lines.append(shape)

    # If the cutouts contain lines we try to first join them together into shapes
    cutout_shapes += lines_to_shapes(cutout_lines)
    polygons = []
    for shape in cutout_shapes:
        if increase_hole_size_by and len(shape) > 2:
            shape = offset_shape(shape, increase_hole_size_by)
        polygons.append(polygon([[x, y] for x, y in shape]))

    return union()(*polygons)
Пример #23
0
    def __init__(self, **kwargs):
        if 'name' not in kwargs.keys():
            kwargs['name'] = 'klann'

        if 'elts' not in kwargs.keys():
            #create
            O, A,B, C, D, E, F,M, b1,b2,b3,b4,conn = create_klann_geometry()
            pos_A, neg_A = joint_from_point(A,"A",1)
            pos_B, neg_B = joint_from_point(B,"B",1)
            pos_C, neg_C = joint_from_point(C,"C",1)
            pos_D, neg_D = joint_from_point(D,"D",1)
            pos_E, neg_E = joint_from_point(E,"E",1)
            pos_F, neg_F = joint_from_point(F,"F",1)
            pos_M, neg_M = joint_from_point(M,"M",1)
            pos_O, neg_O = joint_from_point(O,"O",1)


            b1_body = rationalize_segment(b1,[neg_M, neg_C, neg_D],"b1")
            b2_body = rationalize_segment(b2,[neg_B, neg_E],"b2")
            b3_body = rationalize_segment(b3, [neg_A,pos_C],"b3")
            b4_body = rationalize_segment(b4, [pos_E,pos_D], "b4")
            conn = rationalize_segment(conn, [neg_O, pos_M], "conn" )

            # #create servo mount that connects to shaft connector
            b, j, c = create_klann_part(1,1, "1")
            A,_,B = j
            mt, m_attach, _ = create_servo_mount()
                        # #add support for A,B
            mount_thickness= 3 # shaft coupler
            layer_thickness = 3
            #O, A,B, C, D, E, F,M, b1,b2,b3,b4,conn = create_klann_geometry()

            ##create the attacher thing, with joints
            A_bar, a_attach = create_support_bar(A,mount_thickness)
            B_bar, b_attach = create_support_bar(B,mount_thickness + layer_thickness)

            m_attach_gen = m_attach.get_generator()
            a_gen = a_attach.get_generator()
            b_gen = b_attach.get_generator()

            a_join = solid.hull()(m_attach_gen, a_gen)
            b_join = solid.hull()(m_attach_gen, b_gen)

            cronenberg = PolyMesh(generator= solid.union()(a_join,b_join))
            aparatus = cronenberg + A_bar + B_bar + mt

            shaft_conn = create_shaft_connector()

            OT = (0, 0, 0)
            OQ = (0, 0, 1, 0)
            OP = (OT, OQ)
            bt_pos, bt_neg = joint_from_point(B,"B",2)
            torso = Body(
                pose = OP,
                joints=[
                    pos_A,
                    pos_O, bt_pos
                ],
                elts=[Layer(
                    aparatus,
                    name='lol',
                    color='yellow',
                )],
                name='torso'
            )
            coupler = Body(
                pose = OP,
                joints = [pos_O],
                elts = [Layer(shaft_conn, name='lol', color = 'blue')],
                name = 'coupler'
            )
            kwargs['elts'] = [coupler, b1_body, b2_body, b3_body, b4_body, conn,torso]#[torso]
            #kwargs['children'] = [torso]

        if 'connections' not in kwargs.keys():
            kwargs['connections'] = [
                ((0, 'torso', 'A'),(0, 'b3', 'A')),
                ((0, 'torso', 'B'),(0, 'b2', 'B')),
                ((0,'torso', 'O'),(0, 'conn', 'O')),
                ((0, 'conn','M'),(0,'b1', 'M')),
                ((0,'b1','C'),(0,'b3','C')),
                ((0,'b1','D'), (0,'b4','D')),
                ((0,'b2','E'),(0,'b4','E')),
                ((0,'conn', 'O'), (0,'coupler', 'O'))
            ]
        super(KlannLinkage, self).__init__(**kwargs)
Пример #24
0
    def __init__(self, **kwargs):
        if 'name' not in kwargs.keys():
            kwargs['name'] = 'klann'

        if 'elts' not in kwargs.keys():
            #create

            b1, j1, c1 = create_klann_part(1,1, "1",True)
            b2, j2, c2 = create_klann_part(1, 1+ np.pi/2, "2", True)

            # print(conn.joints)
            A1,_,B1 = j1
            A2,_,B2 = j2
            # A1 = voffset_joint(A1,-3, "1A")
            # B1 = voffset_joint(B1,0,"1B")
            link_bodies = b1+b2
            link_conns = c1+c2
            # # #create servo mount that connects to shaft connector
            mt, m_attach1, m_attach2 = create_servo_mount()
            #             # #add support for A,B
            mount_thickness= 6 # shaft coupler
            layer_thickness = 15
            #
            # ##create the attacher thing, with joints

            #first layer of standoffs
            st_body1,anch1 = standoff(mount_thickness) #contains joint "anchor"
            st_body2,anch2 = standoff(mount_thickness)
            st_body3,_ = standoff(layer_thickness) #contains joint "anchor"
            st_body4,_ = standoff(layer_thickness)
            st_conn1 = ((0,"1b3","1A"),(0,st_body1.name, "A"))
            st_conn2 = ((0,"1b2","1B"),(0,st_body2.name, "A"))

            #second layer:
            st_conn3 = ((0,"2b3", "2A"),(0,st_body3.name, "A"))
            st_conn4 = ((0,"2b2", "2B"),(0,st_body4.name, "A"))

            #A1_bar, a1_attach = create_support_bar(A1,mount_thickness)
            #B1_bar, b1_attach = create_support_bar(B1,mount_thickness + layer_thickness)
            #
            m_attach1_gen = m_attach1.get_generator()
            # b1_gen = b1_attach.get_generator()
            #
            ((dxa,dya,_),_) = A1.pose
            ((dxb,dyb,_),_) = B1.pose
            placed_anch1 = solid.translate([dxa,dya,0])(anch1)
            placed_anch2 = solid.translate([dxb,dyb,0])(anch2)

            a1_join = solid.hull()(m_attach1_gen, placed_anch1)
            b1_join = solid.hull()(m_attach1_gen, placed_anch2)
            #
            cronenberg1 = PolyMesh(generator= solid.union()(a1_join,b1_join))

            aparatus = cronenberg1 +mt

            shaft_conn = create_shaft_connector()

            OT = (0, 0, 0)
            OQ = (0, 0, 1, 0)
            OP = (OT, OQ)

            pos_O, neg_O = joint_from_point(Point(0,0), "1O", 1)
            O_3, _ = joint_from_point(Point(0,0),"3O",5)

            torso = Body(
                pose = OP,
                joints = [pos_O, A1, B1],
                elts=[Layer(
                    aparatus,
                    name='lol',
                    color='yellow',
                )],
                name='torso'
            )
            coupler = Body(
                 pose = OP,
                 joints = [pos_O,O_3],
                 elts = [Layer(shaft_conn, name='lol', color = 'blue')],
                 name = 'coupler'
             )
            kwargs['elts'] = link_bodies+ [coupler]#, st_body1, st_body2, st_body3, st_body4]#,torso]#[torso] [conn,torso]+ , [coupler]+ conn coupler,
            #kwargs['children'] = [torso]

        if 'connections' not in kwargs.keys():
            kwargs['connections'] = [
                ((0, '1conn', '1O'),(0,'coupler','1O')),
                ((0, 'coupler', '3O'),(0, '2conn','2O'))
                #st_conn1,
                #st_conn2,
                #st_conn3,
                #st_conn4
                #((0, 'torso', '2O'),(0, 'conn','2O')),
                # ((0, 'torso', '1A'),(0, '1b3', '1A')),
                # ((0, 'torso', '1B'),(0, '1b2', '1B')),
                #((0, 'torso', '2A'),(0, '2b3', '2A')),
                #((0, 'torso', '2B'),(0, '2b2', '2B'))
            ] + link_conns
        super(DoubleDeckerKlannLinkage, self).__init__(**kwargs)
Пример #25
0
    def __init__(self, **kwargs):
        if 'name' not in kwargs.keys():
            kwargs['name'] = 'klann'

        if 'elts' not in kwargs.keys():
            #create

            b1, j1, c1 = create_klann_part(1,1, "1")
            b2, j2, c2 = create_klann_part(-1, 1, "2") # + np.pi
            conn1 = b1.pop()
            conn2 = b2.pop()
            conn = combine_connectors(conn1,conn2)
            # print(conn.joints)
            A1,_,B1 = j1
            A1 = voffset_joint(A1,-3, "1A")
            B1 = voffset_joint(B1,0,"1B")
            A2,_,B2 = j2
            A2 = voffset_joint(A2, -9, "2A")
            B2 = voffset_joint(B2, -6, "2B")
            link_bodies = b1+b2 +[conn]
            link_conns = c1+c2
            # #create servo mount that connects to shaft connector
            mt, m_attach1, m_attach2 = create_servo_mount()
                        # #add support for A,B
            mount_thickness= 3 # shaft coupler
            layer_thickness = 3

            ##create the attacher thing, with joints
            A1_bar, a1_attach = create_support_bar(A1,mount_thickness)
            B1_bar, b1_attach = create_support_bar(B1,mount_thickness)

            m_attach1_gen = m_attach1.get_generator()
            a1_gen = a1_attach.get_generator()
            b1_gen = b1_attach.get_generator()

            a1_join = solid.hull()(m_attach1_gen, a1_gen)
            b1_join = solid.hull()(m_attach1_gen, b1_gen)

            cronenberg1 = PolyMesh(generator= solid.union()(a1_join,b1_join))

            # A2_bar, a2_attach = create_support_bar(A2,mount_thickness)
            # B2_bar, b2_attach = create_support_bar(B2,mount_thickness)
            #
            # m_attach2_gen = m_attach2.get_generator()
            # a2_gen = a2_attach.get_generator()
            # b2_gen = b2_attach.get_generator()
            #
            # a2_join = solid.hull()(m_attach2_gen, a2_gen)
            # b2_join = solid.hull()(m_attach2_gen, b2_gen)

            # cronenberg2 = PolyMesh(generator= solid.union()(a2_join,b2_join))
            aparatus = cronenberg1 + A1_bar + B1_bar + mt #+ cronenberg2 + A2_bar + B2_bar

            shaft_conn = create_shaft_connector()

            OT = (0, 0, 0)
            OQ = (0, 0, 1, 0)
            OP = (OT, OQ)

            pos_O, neg_O = joint_from_point(Point(0,0), "1O", 1)

            torso = Body(
                pose = OP,
                joints = [pos_O, A2, B2, A1, B1],
                elts=[Layer(
                    aparatus,
                    name='lol',
                    color='yellow',
                )],
                name='torso'
            )
            coupler = Body(
                pose = OP,
                joints = [pos_O],
                elts = [Layer(shaft_conn, name='lol', color = 'blue')],
                name = 'coupler'
            )
            kwargs['elts'] = [torso]+ link_bodies#[torso] , conn coupler,
            #kwargs['children'] = [torso]

        if 'connections' not in kwargs.keys():
            kwargs['connections'] = [
                #((0, 'conn', '1O'),(0,'coupler','1O')),
                #((0, 'torso', '1O'),(0, 'conn','1O')),
                #((0, 'torso', '2O'),(0, 'conn','2O')),
                ((0, 'torso', '1A'),(0, '1b3', '1A')),
                ((0, 'torso', '1B'),(0, '1b2', '1B')),
                ((0, 'torso', '2A'),(0, '2b3', '2A')),
                ((0, 'torso', '2B'),(0, '2b2', '2B'))
            ] + link_conns
        super(DoubleKlannLinkage, self).__init__(**kwargs)
Пример #26
0
    def __init__(self, **kwargs):
        if 'name' not in kwargs.keys():
            kwargs['name'] = 'klann'

        if 'elts' not in kwargs.keys():
            #create


##################################################
##################################################
            b1, j1, c1 = create_klann_part(1,1, "1")
            b2, j2, c2 = create_klann_part(-1, 1+ np.pi, "2")
            conn1 = b1.pop()
            conn2 = b2.pop()
            conn = combine_connectors(conn1,conn2)
            # print(conn.joints)
            A1,_,B1 = j1
            A1 = voffset_joint(A1,-3, "1A")
            B1 = voffset_joint(B1,0,"1B")
            A2,_,B2 = j2
            A2 = voffset_joint(A2, -9, "2A")
            B2 = voffset_joint(B2, -6, "2B")
            link_bodies = b1+b2 +[conn]
            link_conns = c1+c2
            # #create servo mount that connects to shaft connector
            mt, m_attach1, m_attach2 = create_servo_mount()
                        # #add support for A,B
            mount_thickness= 3 # shaft coupler
            layer_thickness = 3

            ##create the attacher thing, with joints
            A1_bar, a1_attach = create_support_bar(A1,mount_thickness)
            B1_bar, b1_attach = create_support_bar(B1,mount_thickness)

            m_attach1_gen = m_attach1.get_generator()
            a1_gen = a1_attach.get_generator()
            b1_gen = b1_attach.get_generator()

            a1_join = solid.hull()(m_attach1_gen, a1_gen)
            b1_join = solid.hull()(m_attach1_gen, b1_gen)

            cronenberg1 = PolyMesh(generator= solid.union()(a1_join,b1_join))

            A2_bar, a2_attach = create_support_bar(A2,mount_thickness)
            B2_bar, b2_attach = create_support_bar(B2,mount_thickness)

            m_attach2_gen = m_attach2.get_generator()
            a2_gen = a2_attach.get_generator()
            b2_gen = b2_attach.get_generator()

            a2_join = solid.hull()(m_attach2_gen, a2_gen)
            b2_join = solid.hull()(m_attach2_gen, b2_gen)

            cronenberg2 = PolyMesh(generator= solid.union()(a2_join,b2_join))
            aparatus = cronenberg1 + A1_bar + B1_bar + mt + cronenberg2 + A2_bar + B2_bar

            OT = (0, 0, 0)
            OQ = (0, 0, 1, 0)
            OP = (OT, OQ)

            pos_O, neg_O = joint_from_point(Point(0,0), "1O", 1)

            torso = Body(
                pose = OP,
                joints = [pos_O, A2, B2, A1, B1],
                elts=[Layer(
                    aparatus,
                    name='lol',
                    color='yellow',
                )],
                name='torso'
            )
            # coupler = Body(
            #     pose = OP,
            #     joints = [pos_O],
            #     elts = [Layer(shaft_conn, name='lol', color = 'blue')],
            #     name = 'coupler'
            # )
            # kwargs['elts'] = [torso]+ link_bodies#[torso] , conn coupler,
            #kwargs['children'] = [torso]

##################################################



            #b3, j3, c3 = create_klann_part(-1,1+ np.pi/2, "3")
            b4, j4, c4 = create_klann_part(1, 1+ np.pi/2, "4", True)

            # print(conn.joints)
            #A3,_,B3 = j3
            A4,_,B4 = j4
            link_bodies = b4+link_bodies
            link_conns =  c4+link_conns
            # # #create servo mount that connects to shaft connector
            #mt, m_attach1, m_attach2 = create_servo_mount()
            #             # #add support for A,B
            mount_thickness= 6 # shaft coupler
            layer_thickness = 15
            #
            # ##create the attacher thing, with joints

            #first layer of standoffs
            #st_body1,anch1 = standoff(mount_thickness) #contains joint "anchor"
            #st_body2,anch2 = standoff(mount_thickness)
            st_body3,_ = standoff(layer_thickness) #contains joint "anchor"
            st_body4,_ = standoff(layer_thickness)
            #st_conn1 = ((0,"1b3","1A"),(0,st_body1.name,"A"))
            #st_conn2 = ((0,"1b2","1B"),(0,st_body2.name,"A"))

            #second layer:
            st_conn3 = ((0,"4b3", "4A"),(0,st_body3.name, "A"))
            st_conn4 = ((0,"4b2", "4B"),(0,st_body4.name, "A"))

            #A1_bar, a1_attach = create_support_bar(A1,mount_thickness)
            #B1_bar, b1_attach = create_support_bar(B1,mount_thickness + layer_thickness)
            #
            #m_attach1_gen = m_attach1.get_generator()
            # b1_gen = b1_attach.get_generator()

            #((dxa,dya,_),_) = A1.pose
            #((dxb,dyb,_),_) = B1.pose
            #placed_anch1 = solid.translate([dxa,dya,0])(anch1)
            #placed_anch2 = solid.translate([dxb,dyb,0])(anch2)

            #a1_join = solid.hull()(m_attach1_gen, placed_anch1)
            #b1_join = solid.hull()(m_attach1_gen, placed_anch2)

            #cronenberg1 = PolyMesh(generator= solid.union()(a1_join,b1_join))

            #aparatus = cronenberg1 +mt

            shaft_conn = create_shaft_connector()

            OT = (0, 0, 0)
            OQ = (0, 0, 1, 0)
            OP = (OT, OQ)

            pos_O, neg_O = joint_from_point(Point(0,0), "1O", 1)
            O_3, _ = joint_from_point(Point(0,0),"3O",5)

            # torso = Body(
            #     pose = OP,
            #     joints = j1+j2,
            #     elts=[Layer(
            #         aparatus,
            #         name='lol',
            #         color='yellow',
            #     )],
            #     name='torso'
            # )
            coupler = Body(
                 pose = OP,
                 joints = [pos_O,O_3],
                 elts = [Layer(shaft_conn, name='lol', color = 'blue')],
                 name = 'coupler'
             )
            kwargs['elts'] = link_bodies+ [coupler, st_body3, st_body4,torso]#[torso] [conn,torso]+ , [coupler]+ conn coupler,
            #kwargs['children'] = [torso]

        if 'connections' not in kwargs.keys():
            kwargs['connections'] = [
                #((0, 'conn', '1O'),(0,'coupler','1O')),
                #((0, 'coupler', '3O'),(0, '4conn','4O')), # 4O?
                #st_conn1,
                #st_conn2,
                st_conn3,
                st_conn4,
                # ((0, 'torso', '1O'),(0, 'coupler','1O')),
                ((0, 'torso', '1A'),(0, '1b3', '1A')),
                ((0, 'torso', '1B'),(0, '1b2', '1B')),
                ((0, 'torso', '2A'),(0, '2b3', '2A')),
                ((0, 'torso', '2B'),(0, '2b2', '2B'))
            ] + link_conns
        super(DoubleDoubleDeckerKlannLinkage, self).__init__(**kwargs)
Пример #27
0
def test_linearizer():
    O,A,B,C,D,E,F,M,b1,b2,b3,b4,conn = create_klann_geometry(1,1)
    b1_dict = {b1: [M,D,C]}
    b2_dict = {b2: [B,E]}
    b3_dict = {b3: [A,C]}
    b4_dict = {b4:[E,D,F]}
    conn_dict = {conn: [M,O]}

    O2,A2,B2,C2,D2,E2,F2,M2,b12,b22,b32,b42,conn2 = create_klann_geometry(-1,1)
    b1_dict2 = {b12: [M2,D2,C2]}
    b2_dict2 = {b22: [B2,E2]}
    b3_dict2 = {b32: [A2,C2]}
    b4_dict2 = {b42:[E2,D2,F2]}

    O3,A3,B3,C3,D3,E3,F3,M3,b13,b23,b33,b43,conn3 = create_klann_geometry(1,1 + np.pi)
    b1_dict3 = {b13: [M3,D3,C3]}
    b2_dict3 = {b23: [B3,E3]}
    b3_dict3 = {b33: [A3,C3]}
    b4_dict3 = {b43:[E3,D3,F3]}

    O4,A4,B4,C4,D4,E4,F4,M4,b14,b24,b34,b44,conn4 = create_klann_geometry(-1,1 + np.pi)
    b1_dict4 = {b14: [M4,D4,C4]}
    b2_dict4 = {b24: [B4,E4]}
    b3_dict4 = {b34: [A4,C4]}
    b4_dict4 = {b44:[E4,D4,F4]}
    conn_dict4 = {conn4:[M4,O4]}
    # seg_paths = simulate_linkage_path(1,1)
    # seg_paths2 = simulate_linkage_path(-1,1)
    # seg_paths3 = simulate_linkage_path(1,1+np.pi)
    # seg_paths4 = simulate_linkage_path(-1,1+np.pi)
    # seg_paths.update(seg_paths2)
    # seg_paths.update(seg_paths3)
    # seg_paths.update(seg_paths4)
    # print("generated Geometry")
    #
    # seg_confs = seg_conflicts(seg_paths)
    # print("calculated conflicts")
    #
    # #add gear conflicts and joints
    gear = Segment(M,M3)
    cap = Segment(M3,M3)
    # seg_confs[b1]+=[gear]
    # seg_confs[b12]+=[gear]
    # seg_confs[b13]+=[gear]
    # seg_confs[b14]+=[gear]
    # seg_confs[gear] = [b1,b12,b13,b14]
    gear_dict = {gear:[M,M3]}
    cap_dict = {cap:[M3]}
    #
    seg_dicts = [b1_dict, b2_dict, b3_dict, b4_dict]
    seg_dicts2 = [b1_dict2, b2_dict2, b3_dict2, b4_dict2]
    seg_dicts3 = [b1_dict3, b2_dict3, b3_dict3, b4_dict3]
    seg_dicts4 = [b1_dict4, b2_dict4, b3_dict4, b4_dict4]
    all_dicts = [gear_dict, conn_dict, cap_dict] + seg_dicts + seg_dicts2 + seg_dicts3 + seg_dicts4
    # print("added gear")
    #
    # neighbor_dicts = {list(seg.keys())[0]: [list(s.keys())[0] for s in all_dicts if shares_joint(s,seg)]
    #                             for seg in all_dicts}

    print("created neighbors")

    #optimal = create_layer_assignment(neighbor_dicts,seg_confs)
    optimal = {}
    optimal[gear] = 0
    optimal[b1] = 1
    optimal[b2] = 1
    optimal[b3] = 2
    optimal[b4] = 2

    optimal[b12] = 2
    optimal[b22] = 2
    optimal[b32] = 1
    optimal[b42] = 1

    optimal[b13] = -2
    optimal[b23] = -2
    optimal[b33] = -1
    optimal[b43] = -1

    optimal[b14] = -1
    optimal[b24] = -1
    optimal[b34] = -2
    optimal[b44] = -2

    optimal[conn] = 3
    optimal[cap] = -3

    lock_joints = [conn,conn2,conn3,conn4,gear, cap]
    anchor_pts = [A,B,O,A4,B4]
    ratts, conns, seg_names, joint_names = rationalize_linkage(all_dicts, optimal, lock_joints, anchor_pts)

    pos_O, neg_O = joint_from_point(Point(0,0), "1O", 1)
    #Create torso
    mt, m_attach1, m_attach2 = create_servo_mount()
                # #add support for A,B
    mount_thickness= 3 # shaft coupler
    layer_thickness = 3

    ##create the attacher thing, with joints
    A1_bar, a1_attach = create_support_bar(joint_from_point(A,"A",3)[0],mount_thickness)
    B1_bar, b1_attach = create_support_bar(joint_from_point(B,"B",2)[0],mount_thickness)

    m_attach1_gen = m_attach1.get_generator()
    a1_gen = a1_attach.get_generator()
    b1_gen = b1_attach.get_generator()

    a1_join = solid.hull()(m_attach1_gen, a1_gen)
    b1_join = solid.hull()(m_attach1_gen, b1_gen)

    cronenberg1 = PolyMesh(generator= solid.union()(a1_join,b1_join))

    A2_bar, a2_attach = create_support_bar(joint_from_point(A2,"A2",2)[0],mount_thickness)
    B2_bar, b2_attach = create_support_bar(joint_from_point(B2,"B2",3)[0],mount_thickness)

    m_attach2_gen = m_attach2.get_generator()
    a2_gen = a2_attach.get_generator()
    b2_gen = b2_attach.get_generator()

    a2_join = solid.hull()(m_attach2_gen, a2_gen)
    b2_join = solid.hull()(m_attach2_gen, b2_gen)

    cronenberg2 = PolyMesh(generator= solid.union()(a2_join,b2_join))
    aparatus = cronenberg1 + A1_bar + B1_bar + mt + cronenberg2 + A2_bar + B2_bar
    aparatus.save("torso.stl")

    OT = (0, 0, 0)
    OQ = Z_JOINT_POSE[1]
    OP = (OT, OQ)


    torso = Body(
        pose = OP,
        joints = [pos_O],
        elts=[Layer(
            aparatus,
            name='lol',
            color='yellow',
        )],
        name='torso'
    )

    ratts += [torso]
    conns += [((0,'torso',"1O"),(0,seg_names[conn], joint_names[O]))]
    #print ratts
    #print conns
    return ratts, conns
Пример #28
0
    def save(self, file):
        # Add screws
        screw_head_radius = 3.0
        screw_head_length = 2.5
        screw_shaft_radius = 1.40       # 2.8mm diameter = 0.3mm extra
        screw_shaft_length = 15.0
        head = sc.translate([0,0,screw_shaft_length])(
                    sc.cylinder(h=screw_head_length + 100, r=screw_head_radius, segments=self._round_segments)
                )
        shaft = sc.cylinder(h=screw_shaft_length + 0.1, r=screw_shaft_radius, segments=self._round_segments)
        screw_down = sc.translate([0,0,-screw_shaft_length - screw_head_length])(
                        sc.union()(head,shaft)
                    )

        # Origin is top of screw
        screw_side = sc.rotate([0,90,0])(screw_down)
        sc.scad_render_to_file(screw_side, "screw.scad", include_orig_code=False)

        # Place 4 screws in the right side
        screw_recess_side = 1.0
        assert screw_recess_side < self._thickness_xy
        side_thick = self._thickness_xy - self._board_slot
        ymin = self._board_bbox.bot() - self._board_slot - side_thick/2.0
        ymax = self._board_bbox.top() + self._board_slot + side_thick/2.0
        zmin = -self.cavity_bot - self._thickness_z + screw_head_radius + self._min_screw_material
        zmax = self.cavity_top - self._thickness_z - screw_head_radius
        x = self._board_bbox.right() + self._thickness_xy + 1.0

        # Add screws to the side
        for y in [ymin, ymax]:
            for z in [zmin, zmax]:
                self._case -= sc.translate([x,y,z])(screw_side)
        print "Free material around side screws: {0}mm".\
            format(self._thickness_xy - self._board_slot - 2*screw_shaft_radius)

        # Add screws to the top
        screw_recess_top = 0
        assert screw_recess_top < self._thickness_z
        min_screw_depth = 3.0

        #Lowest depth screw can possibly go
        zmin = self.cavity_top + screw_head_length + min_screw_depth
        z_want = self.cavity_top + self._thickness_z - screw_recess_top
        z = max(zmin, z_want)

        ys = [self._board_bbox.top() + self._board_slot + (self._thickness_xy - self._board_slot)/2.0,
              self._board_bbox.bot() - self._board_slot - (self._thickness_xy - self._board_slot)/2.0]
        xs = [self._board_bbox.left() + screw_head_radius, self._board_bbox.right() - screw_shaft_length - 1.0]
        for y in ys:
            for x in xs:
                self._case -= sc.translate([x,y,z])(screw_down)

        #Top area: top of the case
        top_area_select = self._board_bbox.copy().pad(self._thickness_xy*2)
        top_area_select = rect2scad(top_area_select, self._thickness_z + 0.1, self.cavity_top - 0.05)

        # main_area is the case without the top or side
        main_area = self._board_bbox.copy()
        main_area.bounds[0][0] -= self._thickness_xy*2
        main_area.bounds[0][1] -= self._thickness_xy*2
        main_area.bounds[1][0] -= 0.05    #So we don't have a degenerate face
        main_area.bounds[1][1] += self._thickness_xy*2
        main_area = rect2scad(main_area, self.height * 2, z_start = -self.height - 10)

        #Add screws to hold down the board
        remove_top = self._board_bbox.copy().pad(self._thickness_xy*2)
        remove_top = rect2scad(remove_top, self.height, self.cavity_top + 0.05)
        x = self._board_bbox.left() + (self._board_bbox.width + self._board_slot*2)/2.0
        ys = [self._board_bbox.bot() - screw_shaft_radius - 0.5,
              self._board_bbox.top() + screw_shaft_radius + 0.5]
        z = screw_head_length
        for y in ys:
            self._case -= (sc.translate([x,y,z])(screw_down) - remove_top)
            print "Board screw location: ({0}, {1})".format(x,y)


        # Separate out the sides of the case
        main_part = self._case * main_area
        side = self._case - (main_area + top_area_select)      # Side of the case, first part to screw on


        #The top of the case (screwed on after the side)
        top = self._case * top_area_select
        main_part -= top_area_select
        sc.scad_render_to_file(top, "top." + file, include_orig_code=False)

        sc.scad_render_to_file(main_part, "main." + file, include_orig_code=False)
        sc.scad_render_to_file(side, "side." + file, include_orig_code=False)

        exploded = sc.union()(
            main_part,
            sc.translate([40,0,0])(side),
            sc.translate([0,0,40])(top)
        )
        sc.scad_render_to_file(exploded, "exploded." + file, include_orig_code=False)
        sc.scad_render_to_file(self._case, file, include_orig_code=False)