Restructure project
This commit is contained in:
283
model/pointer.FCMacro
Normal file
283
model/pointer.FCMacro
Normal file
@@ -0,0 +1,283 @@
|
||||
# IMU Pointer Enclosure
|
||||
|
||||
import FreeCAD as App
|
||||
import FreeCADGui as Gui
|
||||
import Part
|
||||
from FreeCAD import Base
|
||||
|
||||
doc = App.newDocument("pointer")
|
||||
|
||||
# Global dimensions
|
||||
L = 115.0
|
||||
W = 36.0
|
||||
H = 20.0
|
||||
WALL = 3.5
|
||||
CR = 3.0
|
||||
TOL = 0.25
|
||||
|
||||
# Rail and lid
|
||||
RAIL_H = 4.5
|
||||
RAIL_D = 2.0
|
||||
LIP_H = 2.0
|
||||
LIP_OVER = 1.5
|
||||
LIP_EMBED = 0.2
|
||||
|
||||
LID_H = RAIL_H - LIP_H - TOL - 0.55
|
||||
|
||||
# Board dimensions
|
||||
PCB_T = 1.0
|
||||
BRD_L = 21.0
|
||||
BRD_W = 17.5
|
||||
BRD_X = WALL
|
||||
BRD_Y = (W - BRD_W) / 2
|
||||
|
||||
PLATFORM_H = 0.5
|
||||
BRD_Z = WALL + PLATFORM_H
|
||||
|
||||
# Clip arms
|
||||
ARM_LEN = 5.0
|
||||
ARM_THICK = 1.6
|
||||
ARM_H = BRD_Z + PCB_T + 0.8
|
||||
CLIP_TOL = 0.35
|
||||
|
||||
# USB-C cutout
|
||||
USBC_W = 11.0
|
||||
USBC_H = 7.0
|
||||
USBC_Z = 4.5
|
||||
|
||||
# Battery section
|
||||
BAT_L = 50.0
|
||||
BAT_W = 12.0
|
||||
BAT_H = 12.0
|
||||
BAT_X = BRD_X + BRD_L + 8.0
|
||||
BAT_Y = (W - BAT_W) / 2
|
||||
BAT_CLIP_Y = 8.0
|
||||
|
||||
|
||||
# Rounded box helper
|
||||
def rbox(lx, ly, lz, ox=0, oy=0, oz=0, r=CR):
|
||||
b = Part.makeBox(lx, ly, lz, Base.Vector(ox, oy, oz))
|
||||
try:
|
||||
vert = [e for e in b.Edges
|
||||
if abs(e.Vertexes[0].Z - e.Vertexes[1].Z) > lz * 0.9]
|
||||
if vert:
|
||||
b = b.makeFillet(r, vert)
|
||||
except Exception:
|
||||
pass
|
||||
return b
|
||||
|
||||
|
||||
# Simple box helper
|
||||
def box(lx, ly, lz, ox=0, oy=0, oz=0):
|
||||
return Part.makeBox(lx, ly, lz, Base.Vector(ox, oy, oz))
|
||||
|
||||
|
||||
# Rounded slot helper
|
||||
def rounded_slot(depth, w, h, ox, oy, oz, r=None):
|
||||
if r is None:
|
||||
r = h / 2.0
|
||||
|
||||
r = min(r, h / 2.0, w / 2.0)
|
||||
|
||||
import math
|
||||
|
||||
cy = oy + w / 2.0
|
||||
cz = oz + h / 2.0
|
||||
hw = w / 2.0 - r
|
||||
|
||||
def pt(cx, cy_v, cz_v, angle_deg, radius):
|
||||
a = math.radians(angle_deg)
|
||||
return Base.Vector(
|
||||
cx,
|
||||
cy_v + radius * math.cos(a),
|
||||
cz_v + radius * math.sin(a)
|
||||
)
|
||||
|
||||
l_start = pt(ox, cy - hw, cz, 270, r)
|
||||
l_mid = pt(ox, cy - hw, cz, 180, r)
|
||||
l_end = pt(ox, cy - hw, cz, 90, r)
|
||||
arc_left = Part.Arc(l_start, l_mid, l_end).toShape()
|
||||
|
||||
line_top = Part.makeLine(
|
||||
l_end,
|
||||
pt(ox, cy + hw, cz, 90, r)
|
||||
)
|
||||
|
||||
r_start = pt(ox, cy + hw, cz, 90, r)
|
||||
r_mid = pt(ox, cy + hw, cz, 0, r)
|
||||
r_end = pt(ox, cy + hw, cz, 270, r)
|
||||
arc_right = Part.Arc(r_start, r_mid, r_end).toShape()
|
||||
|
||||
line_bot = Part.makeLine(r_end, l_start)
|
||||
|
||||
wire = Part.Wire([arc_left, line_top, arc_right, line_bot])
|
||||
face = Part.Face(wire)
|
||||
|
||||
return face.extrude(Base.Vector(depth, 0, 0))
|
||||
|
||||
|
||||
# Board clip helper
|
||||
def make_clip(corner_x, corner_y, inward_x, inward_y):
|
||||
|
||||
plat_w = ARM_THICK + CLIP_TOL
|
||||
|
||||
plat_x = corner_x if inward_x > 0 else corner_x - plat_w
|
||||
plat_y = corner_y if inward_y > 0 else corner_y - plat_w
|
||||
|
||||
platform = box(
|
||||
plat_w, plat_w,
|
||||
PLATFORM_H + PCB_T,
|
||||
plat_x, plat_y, WALL
|
||||
)
|
||||
|
||||
ax_ox = corner_x if inward_x > 0 else corner_x - ARM_LEN
|
||||
ax_oy = corner_y - ARM_THICK - CLIP_TOL if inward_y > 0 else corner_y + CLIP_TOL
|
||||
arm_x = box(ARM_LEN, ARM_THICK, ARM_H, ax_ox, ax_oy, WALL)
|
||||
|
||||
ay_oy = corner_y if inward_y > 0 else corner_y - ARM_LEN
|
||||
ay_ox = corner_x - ARM_THICK - CLIP_TOL if inward_x > 0 else corner_x + CLIP_TOL
|
||||
arm_y = box(ARM_THICK, ARM_LEN, ARM_H, ay_ox, ay_oy, WALL)
|
||||
|
||||
corner_block_w = ARM_THICK + CLIP_TOL
|
||||
cb_ox = corner_x - corner_block_w if inward_x > 0 else corner_x
|
||||
cb_oy = corner_y - corner_block_w if inward_y > 0 else corner_y
|
||||
|
||||
corner_block = box(
|
||||
corner_block_w, corner_block_w, ARM_H,
|
||||
cb_ox, cb_oy, WALL
|
||||
)
|
||||
|
||||
return platform.fuse(arm_x.fuse(arm_y).fuse(corner_block))
|
||||
|
||||
|
||||
# Base outer body
|
||||
base = rbox(L, W, H)
|
||||
|
||||
# Inner cavity
|
||||
base = base.cut(
|
||||
box(L - WALL * 2, W - WALL * 2, H - WALL,
|
||||
WALL, WALL, WALL)
|
||||
)
|
||||
|
||||
rail_z = H - RAIL_H
|
||||
groove_h = RAIL_H - LIP_H
|
||||
|
||||
# Rail grooves
|
||||
base = base.cut(
|
||||
box(L - WALL * 2, RAIL_D, groove_h,
|
||||
WALL, WALL - RAIL_D, rail_z)
|
||||
)
|
||||
|
||||
base = base.cut(
|
||||
box(L - WALL * 2, RAIL_D, groove_h,
|
||||
WALL, W - WALL, rail_z)
|
||||
)
|
||||
|
||||
# Lid lips
|
||||
lip_z = H - LIP_H
|
||||
|
||||
base = base.fuse(
|
||||
box(L - WALL * 2, LIP_OVER, LIP_H,
|
||||
WALL, WALL, lip_z)
|
||||
)
|
||||
|
||||
base = base.fuse(
|
||||
box(L - WALL * 2, LIP_OVER, LIP_H,
|
||||
WALL, W - WALL - LIP_OVER, lip_z)
|
||||
)
|
||||
|
||||
# Back slot
|
||||
slot_y0 = WALL - RAIL_D
|
||||
slot_yw = W - WALL * 2 + RAIL_D * 2
|
||||
|
||||
base = base.cut(
|
||||
box(WALL + 1.0, slot_yw, RAIL_H,
|
||||
L - WALL, slot_y0, rail_z)
|
||||
)
|
||||
|
||||
# Entry bump
|
||||
BUMP_H = 0.5
|
||||
pad_raw = box(WALL, slot_yw, BUMP_H,
|
||||
L - WALL, slot_y0, rail_z)
|
||||
|
||||
pad_trimmed = pad_raw.common(rbox(L, W, H))
|
||||
base = base.fuse(pad_trimmed)
|
||||
|
||||
# Board clips
|
||||
clip_corners = [
|
||||
(BRD_X, BRD_Y, +1, +1),
|
||||
(BRD_X + BRD_L, BRD_Y, -1, +1),
|
||||
(BRD_X, BRD_Y + BRD_W, +1, -1),
|
||||
(BRD_X + BRD_L, BRD_Y + BRD_W, -1, -1),
|
||||
]
|
||||
|
||||
for cx, cy, ix, iy in clip_corners:
|
||||
base = base.fuse(make_clip(cx, cy, ix, iy))
|
||||
|
||||
# USB-C opening
|
||||
base = base.cut(
|
||||
rounded_slot(
|
||||
WALL * 3,
|
||||
USBC_W,
|
||||
USBC_H,
|
||||
-WALL,
|
||||
W / 2 - USBC_W / 2,
|
||||
USBC_Z
|
||||
)
|
||||
)
|
||||
|
||||
# Battery recess
|
||||
base = base.cut(
|
||||
box(BAT_L, BAT_W, 3.0,
|
||||
BAT_X, BAT_Y, WALL)
|
||||
)
|
||||
|
||||
clip_y_start = BAT_Y + BAT_W / 2 - BAT_CLIP_Y / 2
|
||||
|
||||
base = base.fuse(
|
||||
box(2.0, BAT_CLIP_Y, BAT_H * 0.55,
|
||||
BAT_X - 2.0, clip_y_start, WALL)
|
||||
)
|
||||
|
||||
base = base.fuse(
|
||||
box(2.0, BAT_CLIP_Y, BAT_H * 0.55,
|
||||
BAT_X + BAT_L, clip_y_start, WALL)
|
||||
)
|
||||
|
||||
# Lid
|
||||
TAB_W = RAIL_D - TOL + 0.5
|
||||
LID_L = L - WALL * 2 - TOL
|
||||
LID_EXTRA_TOL = 0.5
|
||||
|
||||
LID_W = (
|
||||
W - WALL * 2
|
||||
- (TOL + LID_EXTRA_TOL) * 2
|
||||
+ TAB_W * 2
|
||||
)
|
||||
|
||||
lid_y0 = WALL + TOL + LID_EXTRA_TOL - TAB_W
|
||||
|
||||
lid = box(LID_L, LID_W, LID_H, 0, lid_y0, 0)
|
||||
|
||||
lid = lid.cut(
|
||||
box(WALL * 2, USBC_W + TOL, LID_H + 0.2,
|
||||
LID_L - WALL,
|
||||
W / 2 - (USBC_W + TOL) / 2,
|
||||
-0.1)
|
||||
)
|
||||
|
||||
lid.translate(Base.Vector(WALL + TOL, 0, rail_z))
|
||||
|
||||
# Final objects
|
||||
base_obj = doc.addObject("Part::Feature", "Pointer_Base")
|
||||
base_obj.Shape = base
|
||||
base_obj.ViewObject.ShapeColor = (0.12, 0.12, 0.14)
|
||||
|
||||
lid_obj = doc.addObject("Part::Feature", "Pointer_Lid")
|
||||
lid_obj.Shape = lid
|
||||
lid_obj.ViewObject.ShapeColor = (0.28, 0.28, 0.34)
|
||||
lid_obj.ViewObject.Transparency = 25
|
||||
|
||||
doc.recompute()
|
||||
Gui.activeDocument().activeView().viewIsometric()
|
||||
Gui.SendMsgToActiveView("ViewFit")
|
||||
Reference in New Issue
Block a user