Skip to content

Commit

Permalink
Dual Wrist Rests, Grid
Browse files Browse the repository at this point in the history
  • Loading branch information
rianadon committed Jul 14, 2024
1 parent 2ec073f commit 1624054
Show file tree
Hide file tree
Showing 11 changed files with 160 additions and 74 deletions.
1 change: 1 addition & 0 deletions src/lib/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const codeError = writable<Error | null>(null)
export const hoveredKey = writable<number | null>(null)
export const clickedKey = writable<number | null>(null)

export const showGrid = writable(false)
export const noWall = writable(false)
export const noBase = writable(false)
export const noBlanks = writable(false)
Expand Down
21 changes: 11 additions & 10 deletions src/lib/worker/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,20 +246,21 @@ export async function generateBoardHolder(config: Cuttleform) {
return result
}

export async function generateWristRest(config: Cuttleform) {
export async function generateWristRest(config: Cuttleform, flip = false) {
await ensureOC()
if (!config.wristRest) return NULL
const rest = wristRest(config, newGeometry(config)) as Solid
const name = flip ? 'wristRestLeft' : 'wristRestRight'
if (!config[name]) return NULL
const rest = wristRest(config, newGeometry(config), name) as Solid
const result = meshWithVolume(rest)
rest.delete()
return result
}

export async function generateMirroredWristRest(config: Cuttleform) {
await ensureOC()
if (!config.wristRest) return NULL
if (!config.wristRestLeft) return NULL
config.keys.forEach(k => k.position = new ETrsf(k.position.history).mirror([1, 0, 0]))
const rest = wristRest(config, newGeometry(config)).mirror('YZ', [0, 0, 0])
const rest = wristRest(config, newGeometry(config), 'wristRestLeft').mirror('YZ', [0, 0, 0])
const result = meshWithVolume(rest)
rest.delete()
return result
Expand Down Expand Up @@ -297,7 +298,7 @@ async function getModel(conf: Cuttleform, name: string, stitchWalls: boolean, fl
} else if (name == 'holder') {
return boardHolder(conf, geometry).translateZ(-geometry.floorZ)
} else if (name == 'wristrest') {
return wristRest(conf, geometry).translateZ(-geometry.floorZ)
return wristRest(conf, geometry, flip ? 'wristRestLeft' : 'wristRestRight').translateZ(-geometry.floorZ)
} else {
throw new Error("I don't know what model you want")
}
Expand All @@ -306,9 +307,9 @@ async function getModel(conf: Cuttleform, name: string, stitchWalls: boolean, fl
export async function getSTL(conf: Cuttleform, name: string, side: 'left' | 'right' | 'unibody') {
const flip = side == 'left'
let model = await getModel(conf, name, true, flip)
if (name == 'wristrest' && side == 'unibody' && conf.wristRest && model) {
if (name == 'wristrest' && side == 'unibody' && conf.wristRestRight && model) {
conf.keys.forEach(k => k.position = new ETrsf(k.position.history).mirror([1, 0, 0]))
model = (model as Solid).fuse(wristRest(conf, newGeometry(conf)).mirror('YZ', [0, 0, 0]))
model = (model as Solid).fuse(wristRest(conf, newGeometry(conf), 'wristRestLeft').mirror('YZ', [0, 0, 0]))
}
if (!model) throw new Error(`Model ${name} is empty`)
if (flip) model = model.mirror('YZ', [0, 0, 0])
Expand All @@ -324,8 +325,8 @@ export async function getSTEP(conf: Cuttleform, flip: boolean, stitchWalls: bool
assembly.add('Microcontroller Holder', boardHolder(conf, geometry))
}

if (conf.wristRest && (await getUser()).sponsor) {
assembly.add('Wrist Rest', wristRest(conf, geometry))
if (conf.wristRestRight && (await getUser()).sponsor) {
assembly.add('Wrist Rest', wristRest(conf, geometry, flip ? 'wristRestLeft' : 'wristRestRight'))
}

assembly = assembly.transform(new Trsf().translate(0, 0, -geometry.floorZ))
Expand Down
70 changes: 59 additions & 11 deletions src/lib/worker/config.cosmos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,20 @@ export type CosmosKey = {
sizeA?: number
sizeB?: number
}

interface CosmosWristRestProps {
angle: number
taper: number
tenting: number
slope: number
stilts?: boolean

maxWidthLeft: number
maxWidthRight: number
extensionLeft: number
extensionRight: number
}

export type CosmosKeyboard =
& {
curvature: Required<CosmosCurvature>
Expand All @@ -95,7 +109,7 @@ export type CosmosKeyboard =
shell: AnyShell
wristRestEnable: boolean
unibody: boolean
wristRestProps: Exclude<Cuttleform['wristRest'], undefined>
wristRestProps: CosmosWristRestProps
wristRestPosition: bigint
connectorIndex: number
}
Expand Down Expand Up @@ -314,17 +328,30 @@ export function toCosmosConfig(conf: Cuttleform, side: 'left' | 'right' | 'unibo
verticalClearance: conf.verticalClearance,
rounded: conf.rounded,
shell: conf.shell,
wristRestEnable: !!conf.wristRest,
wristRestEnable: !!conf.wristRestRight,
connectorIndex: conf.connectorIndex,
unibody: side == 'unibody',
wristRestProps: conf.wristRest || {
angle: 0,
taper: 10,
slope: 5,
maxWidth: 100,
tenting: 6,
extension: 8,
},
wristRestProps: conf.wristRestRight
? {
angle: conf.wristRestRight.angle,
taper: conf.wristRestRight.taper,
slope: conf.wristRestRight.slope,
maxWidthRight: conf.wristRestRight.maxWidth,
maxWidthLeft: conf.wristRestLeft?.maxWidth ?? 100,
tenting: conf.wristRestRight.tenting,
extensionRight: conf.wristRestRight.extension,
extensionLeft: conf.wristRestLeft?.extension ?? 6,
}
: {
angle: 0,
taper: 10,
slope: 5,
maxWidthLeft: 100,
maxWidthRight: 100,
tenting: 6,
extensionLeft: 8,
extensionRight: 8,
},
wristRestPosition: overrideWristRest ? KEYBOARD_DEFAULTS.wristRestPosition! : encodeTuple(wrOrigin.xyz().map(t => Math.round(t * 10))),
clusters: side == 'unibody'
? [
Expand Down Expand Up @@ -408,7 +435,28 @@ export function sideFromCosmosConfig(c: CosmosKeyboard, side: 'left' | 'right' |
microcontroller: c.microcontroller,
microcontrollerAngle: c.microcontrollerAngle,
fastenMicrocontroller: c.fastenMicrocontroller,
wristRest: c.wristRestEnable ? { ...c.wristRestProps } : undefined,
wristRestLeft: c.wristRestEnable
? {
angle: c.wristRestProps.angle,
taper: c.wristRestProps.taper,
tenting: c.wristRestProps.tenting,
slope: c.wristRestProps.slope,

maxWidth: c.wristRestProps.maxWidthLeft,
extension: c.wristRestProps.extensionLeft,
}
: undefined,
wristRestRight: c.wristRestEnable
? {
angle: c.wristRestProps.angle,
taper: c.wristRestProps.taper,
tenting: c.wristRestProps.tenting,
slope: c.wristRestProps.slope,

maxWidth: c.wristRestProps.maxWidthRight,
extension: c.wristRestProps.extensionRight,
}
: undefined,
wristRestOrigin: new ETrsf().translate(wrPos[0] / 10, wrPos[1] / 10, wrPos[2] / 10),
shell: c.shell,
}
Expand Down
18 changes: 12 additions & 6 deletions src/lib/worker/config.serialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,12 @@ const KEYBOARD_EXTRA_DEFAULTS: KeyboardExtra = {
roundedTopVertical: 67,
wristRestAngle: 0,
wristRestTaper: 450,
wristRestMaxWidth: 1000,
wristRestLeftMaxWidth: 1000,
wristRestRightMaxWidth: 1000,
wristRestTenting: 270,
wristRestSlope: 225,
wristRestExtension: 80,
wristRestLeftExtension: 80,
wristRestRightExtension: 80,
connectorIndex: -10,
screwIndices: [],
microcontrollerAngle: 0,
Expand Down Expand Up @@ -408,10 +410,12 @@ export function decodeConfigIdk(b64: string): CosmosKeyboard {
wristRestProps: {
angle: keebExtra.wristRestAngle / 45,
taper: keebExtra.wristRestTaper / 45,
maxWidth: keebExtra.wristRestMaxWidth / 10,
maxWidthLeft: keebExtra.wristRestLeftMaxWidth / 10,
maxWidthRight: keebExtra.wristRestRightMaxWidth / 10,
tenting: keebExtra.wristRestTenting / 45,
slope: keebExtra.wristRestSlope / 45,
extension: keebExtra.wristRestExtension / 10,
extensionLeft: keebExtra.wristRestLeftExtension / 10,
extensionRight: keebExtra.wristRestRightExtension / 10,
},
wristRestPosition: keeb.wristRestPosition,
connectorIndex: keebExtra.connectorIndex / 10,
Expand Down Expand Up @@ -593,9 +597,11 @@ export function encodeCosmosConfig(conf: CosmosKeyboard): Keyboard {
wristRestAngle: Math.round(conf.wristRestProps.angle * 45),
wristRestTaper: Math.round(conf.wristRestProps.taper * 45),
wristRestTenting: Math.round(conf.wristRestProps.tenting * 45),
wristRestMaxWidth: Math.round(conf.wristRestProps.maxWidth * 10),
wristRestLeftMaxWidth: Math.round(conf.wristRestProps.maxWidthLeft * 10),
wristRestRightMaxWidth: Math.round(conf.wristRestProps.maxWidthRight * 10),
wristRestSlope: Math.round(conf.wristRestProps.slope * 45),
wristRestExtension: Math.round(conf.wristRestProps.extension * 10),
wristRestLeftExtension: Math.round(conf.wristRestProps.extensionLeft * 10),
wristRestRightExtension: Math.round(conf.wristRestProps.extensionRight * 10),
connectorIndex: Math.round(conf.connectorIndex * 10),
screwIndices: conf.screwIndices.some(c => c >= 0) ? conf.screwIndices.map(i => Math.round(i * 10) + 10) : [],
roundedSideConcavity: conf.rounded.side ? Math.round(conf.rounded.side.concavity * 10) : undefined,
Expand Down
54 changes: 35 additions & 19 deletions src/lib/worker/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,22 @@ const X: Point = [1, 0, 0]
const Y: Point = [0, 1, 0]
const Z: Point = [0, 0, 1]

interface WristRest {
/** Angle at which the wrist rest is attached to the keyboard */
angle: number
/** Angle at which the wrist rest sides are tapered inwards */
taper: number
/** Maximum width of the wrist rest */
maxWidth: number
/** Angle at which the wrist rest is tented */
tenting: number
/** Angle at which the wrist rests slopes down towards the wrist */
slope: number
/** Amount by which the wrist rests sticks out past the wrist */
extension: number
stilts?: boolean
}

export interface SpecificCuttleform<S> {
wallThickness: number
wallShrouding: number
Expand All @@ -74,21 +90,8 @@ export interface SpecificCuttleform<S> {
screwType: 'screw insert' | 'tapered screw insert' | 'expanding screw insert' | 'tapped hole'
screwSize: 'M3' | 'M4' | '#4-40' | '#6-32'
screwCountersink: boolean
wristRest?: {
/** Angle at which the wrist rest is attached to the keyboard */
angle: number
/** Angle at which the wrist rest sides are tapered inwards */
taper: number
/** Maximum width of the wrist rest */
maxWidth: number
/** Angle at which the wrist rest is tented */
tenting: number
/** Angle at which the wrist rests slopes down towards the wrist */
slope: number
/** Amount by which the wrist rests sticks out past the wrist */
extension: number
stilts?: boolean
}
wristRestLeft?: WristRest
wristRestRight?: WristRest
wristRestOrigin: ETrsf
microcontroller: MicrocontrollerName
/* Angle at which microcontroller should be placed */
Expand Down Expand Up @@ -312,7 +315,20 @@ export function cuttleConf(c: DeepRequired<CuttleformProto>): Cuttleform {
connector: MAP_CONNECTOR[c.wall.connector],
connectorSizeUSB: MAP_CONNECTOR_SIZE[c.wall.connectorSizeUsb],
connectorIndex: -1,
wristRest: c.wall.wristRest
wristRestRight: c.wall.wristRest
? {
// length: c.wall.wristRestLength / 10,
maxWidth: c.wall.wristRestMaxWidth / 10,
// xOffset: c.wall.wristRestXOffset / 10,
// zOffset: c.wall.wristRestZOffset / 10,
angle: 0,
taper: c.wall.wristRestAngle / 45,
tenting: c.curvature.tenting / 45 / 2 + c.wall.wristRestTenting / 45,
slope: 5,
extension: 8,
}
: undefined,
wristRestLeft: c.wall.wristRest
? {
// length: c.wall.wristRestLength / 10,
maxWidth: c.wall.wristRestMaxWidth / 10,
Expand Down Expand Up @@ -1502,12 +1518,12 @@ export function fullEstimatedCenter(geo: FullGeometry | undefined, withWristRest
const defaultCenter = { left: [0, 0, 0] as Point, unibody: [0, 0, 0] as Point, right: [0, 0, 0] as Point }
if (!geo) return { left: defaultCenter, both: defaultCenter, right: defaultCenter }
if (geo.unibody) {
const center = estimatedCenter(geo.unibody, withWristRest && !!geo.unibody!.c.wristRest)
const center = estimatedCenter(geo.unibody, withWristRest && !!geo.unibody!.c.wristRestRight)
const modelCenters = { unibody: center }
return { left: modelCenters, both: modelCenters, right: modelCenters }
} else {
const leftBB = estimatedBB(geo.left!, withWristRest && !!geo.left!.c.wristRest)
const rightBB = estimatedBB(geo.right!, withWristRest && !!geo.right!.c.wristRest)
const leftBB = estimatedBB(geo.left!, withWristRest && !!geo.left!.c.wristRestRight)
const rightBB = estimatedBB(geo.right!, withWristRest && !!geo.right!.c.wristRestRight)
const sepDiff = (VIEW_SEPARATION - (rightBB[0] + leftBB[0])) / 2
return {
left: {
Expand Down
20 changes: 10 additions & 10 deletions src/lib/worker/geometry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1444,13 +1444,13 @@ function transformCriticalPoint(pt: WallCriticalPoints, trsf: Trsf): WallCritica
}
}

export function wristRestGeometry(c: Cuttleform, geo: Geometry) {
if (!c.wristRest) throw new Error('Wrist rest is not enabled')
export function wristRestGeometry(c: Cuttleform, geo: Geometry, wrSide: 'wristRestRight' | 'wristRestLeft') {
if (!c[wrSide]) throw new Error('Wrist rest is not enabled')

// Form the wrist rest by considering all walls roated by the wrist rest angle
// At the end of the function, everything is rotated back.
const origin = new ETrsf(c.wristRestOrigin.history).evaluate({ flat: false }).xyz()
const walls = geo.allWallCriticalPoints().map(p => transformCriticalPoint(p, new Trsf().rotate(-c.wristRest!.angle, origin, [0, 0, 1])))
const walls = geo.allWallCriticalPoints().map(p => transformCriticalPoint(p, new Trsf().rotate(-c[wrSide]!.angle, origin, [0, 0, 1])))

const xMin = new Set<number>()
const xMax = new Set<number>()
Expand All @@ -1467,8 +1467,8 @@ export function wristRestGeometry(c: Cuttleform, geo: Geometry) {
})
const midFrontWall = frontWalls[Math.floor(frontWalls.length / 2)]

const left = Math.max(origin[0] - c.wristRest.maxWidth / 2, Math.min(...xMin))
const right = Math.min(origin[0] + c.wristRest.maxWidth / 2, Math.max(...xMax))
const left = Math.max(origin[0] - c[wrSide].maxWidth / 2, Math.min(...xMin))
const right = Math.min(origin[0] + c[wrSide].maxWidth / 2, Math.max(...xMax))
if (left > right) throw new Error('Wrist rest is not wide enough')

const leftWallY = wallXToY(walls, left, walls.indexOf(midFrontWall), 1, -1, 'to')
Expand All @@ -1478,9 +1478,9 @@ export function wristRestGeometry(c: Cuttleform, geo: Geometry) {

if (!leftWallY || !rightWallY || !leftWallY2 || !rightWallY2) throw new Error('Could not locate walls for wrist rest')

const sinAngle = Math.sin(c.wristRest.taper * Math.PI / 180)
const cosAngle = Math.cos(c.wristRest.taper * Math.PI / 180)
const tanAngle = Math.tan(c.wristRest.taper * Math.PI / 180)
const sinAngle = Math.sin(c[wrSide].taper * Math.PI / 180)
const cosAngle = Math.cos(c[wrSide].taper * Math.PI / 180)
const tanAngle = Math.tan(c[wrSide].taper * Math.PI / 180)

const leftStart = new Vector(left, Math.max(leftWallY.y, leftWallY2.y), 0)
const rightStart = new Vector(right, Math.max(rightWallY.y, rightWallY2.y), 0)
Expand All @@ -1498,7 +1498,7 @@ export function wristRestGeometry(c: Cuttleform, geo: Geometry) {
}

const minY = Math.min(leftStart.y, rightStart.y)
const length = minY - origin[1] + c.wristRest.extension
const length = minY - origin[1] + c[wrSide].extension
const leftLength = (length + leftStart.y - minY) / cosAngle
const rightLength = (length + rightStart.y - minY) / cosAngle

Expand All @@ -1511,7 +1511,7 @@ export function wristRestGeometry(c: Cuttleform, geo: Geometry) {
rightEnd.x = middle + 10
// throw new Error('Wrist rest width is not big enough to support taper angle')
}
const rotateBack = new Trsf().rotate(c.wristRest!.angle, origin, [0, 0, 1])
const rotateBack = new Trsf().rotate(c[wrSide]!.angle, origin, [0, 0, 1])
return {
leftStart: rotateBack.apply(leftStart),
leftEnd: rotateBack.apply(leftEnd),
Expand Down
6 changes: 4 additions & 2 deletions src/proto/cosmos.proto
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,11 @@ message KeyboardExtra {
optional int32 rounded_top_horizontal = 7;
optional int32 rounded_top_vertical = 8;

optional int32 wrist_rest_extension = 9;
optional int32 wrist_rest_left_extension = 9;
optional int32 wrist_rest_right_extension = 16;
optional sint32 wrist_rest_taper = 10;
optional int32 wrist_rest_max_width= 11;
optional int32 wrist_rest_left_max_width = 11;
optional int32 wrist_rest_right_max_width = 17;
optional sint32 wrist_rest_angle = 12;
optional sint32 wrist_rest_slope = 13;
optional sint32 wrist_rest_tenting = 14;
Expand Down
Loading

0 comments on commit 1624054

Please sign in to comment.