cadquery/notebook_casera/modelo.py

190 lines
5.7 KiB
Python
Raw Normal View History

2022-07-22 00:25:32 +00:00
import cadquery2 as cq
from cadquery2 import exporters
from math import floor, atan, pi
# Naming convention
# _l means Y
# _w means X
# _h means Z
shell_t = 2 # Shell thickness
front_h = 25 # height at the front (near user)
back_h = 40 # height at the back (away from user)
width = 290 # width of the whole thing
fillet_s = 4 # Fillet of case sides
kbd_base_l = 150 # length of the front half of the case
screen_base_l = 100 # length of the back half of the case
kbd_angle = atan((back_h - front_h) / kbd_base_l) * 180 / pi
print("kbd_angle=", kbd_angle)
# Added an extra 1mm on each direction for tolerance to make sure it slots in
kbd_w = 202 # width of the keyboard itself
kbd_l = 127 # "length" of the keyboard
kbd_h = 4 # depth of the keyboard holder cutoff
kbd_fillet = 10 # width of the kbd corner fillet
# battery dimensions (mx7)
bat_w = 60
bat_l = 140
bat_h = 22
# width, length VISIBLE WITHIN THE BEZEL
screen_w = 223
screen_l = 57
screen_left_margin = 10 # Distance from the left of the case to screen cutout
# width, length, height INCLUDING_BEZEL
display_w = 233
display_l = 65
display_h = 5
# Distance from the left of the case to display end (7 is bezel width on that side)
display_left_margin = screen_left_margin - 7
# Distance from the right of the case to display end
display_right_margin = width - display_left_margin - display_w
# Distance from the top of the case to display top
display_top_margin = (screen_base_l - display_l) / 2
display_bottom_margin = display_top_margin # Symmetrical
kbd_cutout = (
cq.Sketch().trapezoid(kbd_w, kbd_l, 90).reset().vertices().fillet(kbd_fillet)
)
bat_holder_top = (
cq.Sketch()
.trapezoid(bat_w + 2 * shell_t, bat_h + 2 * shell_t, 90)
.trapezoid(bat_w, bat_h, 90, mode="s")
.trapezoid(bat_w + 10, bat_h - 10, 90, mode="s")
)
# Base to hold (magnetically?) the keyboard (half the case)
kbd_base = (
cq.Workplane("left")
.lineTo(0, kbd_base_l)
.lineTo(front_h, kbd_base_l)
.lineTo(back_h, 0)
.close()
.extrude(width)
.edges("+Z")
.fillet(fillet_s)
.edges("+Y")
.fillet(fillet_s)
# Cut kbd holder area from top face
.faces(">Z")
.workplane(centerOption="CenterOfBoundBox")
.center((screen_w - width) / 2 + screen_left_margin, 0)
.placeSketch(kbd_cutout)
.cutBlind(-kbd_h)
# Make it hollow
.faces("<Y")
.shell(-shell_t)
# Add battery holder
.faces("<Y")
.workplane(centerOption="CenterOfBoundBox", offset=-1)
# The final constants are fudging because it impinges on the surface
.center(
-(width - bat_w - 2 * shell_t) / 2 + 1,
(back_h - bat_h - 2 * shell_t) / 2 - 0.25,
)
.transformed(rotate=cq.Vector(-kbd_angle, 0, 0))
.placeSketch(bat_holder_top)
# The 3 is fudging so the bottom of the holder doesn't
# impinge on the bottom face
.extrude(-(bat_l - 3 * fillet_s))
)
# Slots for ventilation, applied at the bottom of the screen base
ventilacion = (
cq.Sketch() # slots are 3mm separated 5
.rarray(8, 6, floor(width / 9), 1)
.trapezoid(3, 0.8 * screen_base_l, 90, mode="a")
.reset()
.vertices()
.fillet(1)
)
screen_cutout = (
cq.Sketch().trapezoid(screen_w, screen_l, 90, mode="a").reset().vertices().fillet(1)
)
shelf_cutout = (
cq.Sketch()
.trapezoid(width - 2 * shell_t, screen_l, 90, mode="a")
.reset()
.vertices()
.fillet(1)
)
screen_lateral_stop = (
cq.Sketch()
.rarray(display_l - 2 * shell_t, 1, 2, 1)
.trapezoid(2 * shell_t, display_h + 2 * shell_t, 90, mode="a")
)
screen_vertical_stop = cq.Sketch().trapezoid(width, 2 * shell_t, 90, mode="a")
# Holder for the screen (other half of the case)
screen_base = (
# Basic filleted box shape
cq.Workplane("bottom")
.lineTo(-width, 0)
.lineTo(-width, back_h)
.lineTo(0, back_h)
.close()
.extrude(screen_base_l)
.edges("|Y and <Z")
.fillet(fillet_s)
.faces(">Y")
.shell(-shell_t)
# Account for outer shell thickness in offset
.faces(">Z")
.workplane(offset=-display_h - shell_t)
# Add friction shelve for screen assembly
.lineTo(-width, 0)
.lineTo(-width, -screen_base_l)
.lineTo(0, -screen_base_l)
.close()
.extrude(-shell_t)
# Cutout visible screen area from top face
.faces(">Z")
.workplane(centerOption="CenterOfBoundBox")
.center((width - screen_w) / 2 - screen_left_margin, 0)
.placeSketch(screen_cutout)
.cutBlind(-shell_t)
# Cut screen "shelf" to allow for cable routing
.faces(">Z")
.workplane(centerOption="CenterOfBoundBox", offset=-display_h - shell_t)
.placeSketch(shelf_cutout)
.cutBlind(-shell_t)
# Stop the screen from sliding back and forward
.faces(">Y")
.workplane(centerOption="CenterOfBoundBox")
.center(0, back_h / 2 - display_h - shell_t)
.placeSketch(screen_vertical_stop)
.extrude(-display_bottom_margin)
.faces("<Y")
.workplane(centerOption="CenterOfBoundBox")
.center(0, back_h / 2 - display_h - shell_t)
.placeSketch(screen_vertical_stop)
.extrude(-display_top_margin)
# Stop the screen from sliding left and right
.faces(">X")
.workplane(centerOption="CenterOfBoundBox")
.center(0, back_h / 2 - display_h - shell_t)
.placeSketch(screen_lateral_stop)
.extrude(-display_left_margin)
.faces("<X")
.workplane(centerOption="CenterOfBoundBox")
.center(0, back_h / 2 - display_h - shell_t)
.placeSketch(screen_lateral_stop)
.extrude(-display_right_margin)
# Place ventilation grid in bottom face
.faces("<Z")
.workplane(centerOption="CenterOfBoundBox")
.placeSketch(ventilacion)
.cutBlind(-5)
)
exporters.export(screen_base, "screen_base.stl")
exporters.export(kbd_base, "kbd_base.stl")