muse/book-reading-clip-lamp

A tscircuit package created by muse.

Version
0.4.6
License
unset
Stars
0

base-service-connectors.ts

import { box, cyl, move, turn, union, subtract, tint, type Plan, type V3 } from "./mechanical-primitives"
import type { MechanicalPart } from "./enclosure-geometry"

/** Drawing-based external models, NOT vendor STEP. 222 blocks each join ONE
 * potential: never insert different nets in different holes of the same block.
 * Wire-entry detail is a visual approximation; envelope dimensions are catalog.
 */
const wago = (id: string, net: string, center: V3, count = 2, angle = 0) => ({
  id, label: `${net} · WAGO 222-${count === 5 ? "415" : "412"}`,
  family: "WAGO 222", parts: [count === 5 ? "222-415" : "222-412"], center,
  size: [count === 5 ? 26.6 : 12.4, 20.5, 14.5] as V3,
  pitch: 5.1, rows: 1, circuits: count, nets: Array(count).fill(net) as string[], angle,
  source: `https://www.wago.com/us/wire-splicing-connectors/splicing-connector/p/222-${count === 5 ? "415" : "412"}`,
})
export const baseServiceConnectors = [
  wago("vbat-splice", "VBAT", [-15,-148,-180.4]),
  wago("ntc-splice", "NTC", [0,-148,-180.4]),
  wago("ntc-return-splice", "NTC_RETURN", [15,-148,-180.4]),
  wago("ground-splice", "GND", [-11,-177,-180.4], 5),
  wago("chat-splice", "ASK_REMOTE", [15,-186,-180.4], 2, -Math.PI/2),
  wago("power-splice", "PWR_REMOTE", [15,-171,-180.4], 2, -Math.PI/2),
  { id:"speaker-service-connector",label:"Speaker · PicoBlade 51021 / 51047",family:"Molex PicoBlade",
    parts:["0510210200 (speaker)","0510470200 (harness)"],center:[-23.3,-164.5,-167.6] as V3,
    size:[4.25,13.8,4.2] as V3,pitch:1.25,rows:1,circuits:2,nets:["SPK_P","SPK_N"],angle:0,
    source:"https://www.molex.com/en-us/products/part-detail/510470200" },
]
function place(c: typeof baseServiceConnectors[number], p: V3): V3 {
  const a=c.angle
  return [c.center[0]+p[0]*Math.cos(a)-p[1]*Math.sin(a),c.center[1]+p[0]*Math.sin(a)+p[1]*Math.cos(a),c.center[2]+p[2]]
}
export function splicePort(id: string, cavity: number): V3 {
  const c=baseServiceConnectors.find(c=>c.id===id)
  if(!c || cavity<0 || cavity>=c.circuits) throw new Error(`Invalid terminal ${id}.${cavity}`)
  return place(c,[(cavity-(c.circuits-1)/2)*c.pitch,c.size[1]/2,-2])
}
// Legacy logical branch names preserved for the head-harness endpoint audit.
export function connectorPort(id: string,index: number,side:"head"|"load"):V3 {
  if(id==="speaker-service-connector") {
    const c=baseServiceConnectors.find(c=>c.id===id)!
    return [c.center[0]+(index-.5)*1.25,c.center[1]+(side==="head"?1:-1)*c.size[1]/2,c.center[2]]
  }
  if(id==="battery-service-connector") return splicePort(["vbat-splice","ground-splice","ntc-splice","ntc-return-splice"][index],side==="head"?0:1)
  if(id==="chat-service-connector") return index===0?splicePort("chat-splice",side==="head"?0:1):splicePort("ground-splice",2)
  if(id==="power-service-connector") return index===0?splicePort("power-splice",side==="head"?0:1):splicePort("ground-splice",3)
  throw new Error(`Unknown branch ${id}`)
}
/** Ownership split: speaker's supplied housing moves with the speaker;
 * harness-side plug stays with its cable. These share the old mated envelope.
 */
export function speakerConnectorHousing(side:"head"|"load"):Plan {
 const c=baseServiceConnectors.find(c=>c.id==="speaker-service-connector")!
 const shell=side==="load" ? union(box([4.25,8,3.3],[0,-2.9,-.3]),box([2.9,3,.55],[0,-1,1.6])) : box([4.1,5.8,4.2],[0,4,0])
 return move(c.center,tint([.91,.90,.82],subtract(shell,...[-.625,.625].map(x=>move([x,0,0],turn([Math.PI/2,0,0],{type:"cylinder",radius:.48,height:14,segments:20}))))))
}
const model=(c:typeof baseServiceConnectors[number]):Plan=> {
  const [w,d,h]=c.size
  if(c.family!=="WAGO 222") return speakerConnectorHousing("head")
  const holes=Array.from({length:c.circuits},(_,i)=>move([(i-(c.circuits-1)/2)*c.pitch,d/2-5,-2],turn([Math.PI/2,0,0],{type:"cylinder",radius:1.65,height:10.2,segments:24})))
  const body=subtract(box([w,d,h-2],[0,0,-1]),...holes,
    ...Array.from({length:c.circuits},(_,i)=>box([3.8,13,2],[(i-(c.circuits-1)/2)*c.pitch,-1,5.4])))
  const levers=Array.from({length:c.circuits},(_,i)=>tint([1,.10,.004],union(
    box([3.6,14.4,1.8],[(i-(c.circuits-1)/2)*c.pitch,-1,6.35]),
    box([3.6,1.3,2.1],[(i-(c.circuits-1)/2)*c.pitch,6,5.6]))))
  return move(c.center,turn([0,0,c.angle],union(tint([.12,.13,.12],body),...levers)))
}
export const serviceConnectorParts:MechanicalPart[]=baseServiceConnectors.map(c=>({id:c.id,label:c.label,plan:model(c),group:"reference",color:[.48,.49,.48],multicolor:true,printable:false,explode:c.family==="WAGO 222"?[0,0,8]:[0,0,0],note:c.family==="WAGO 222"?`${c.parts[0]}; ${c.size.join(" x ")} mm catalog envelope. ONE potential per block; 28–12 AWG; strip 9–10 mm. Open levers with lid/cradle removed; drawing-based exterior, internal clamp omitted.`:"Harness-side Molex 51047 plug only; stock 51021 receptacle belongs to the speaker assembly. Drawing-based exterior; verify shipped mating, polarity and latch."}))

/** Visible bare conductor inserted into a stock lever clamp; the housing's
 * entry bores already reserve this 9.5 mm strip length. No soldered splice.
 */
export function terminalMetalEnd(points:V3[], conductorRadius:number):Plan[] {
 const end=points[points.length-1]
 for(const c of baseServiceConnectors.filter(c=>c.family==="WAGO 222"))for(let i=0;i<c.circuits;i++) {
  const entry=splicePort(c.id,i)
  if(Math.hypot(...entry.map((n,j)=>n-end[j]))>1e-7)continue
  const localX=(i-(c.circuits-1)/2)*c.pitch
  const at=place(c,[localX,c.size[1]/2-4.75,-2])
  return [move(at,turn([Math.PI/2,0,c.angle],tint([.72,.32,.055],{type:"cylinder",radius:conductorRadius,height:9.5,segments:16})))]
 }
 return []
}