jscad-electronics 0.0.192 → 0.0.193

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cables.d.ts CHANGED
@@ -53,10 +53,13 @@ type CableMesh = {
53
53
  };
54
54
 
55
55
  /** Mesh generation only. Path samples are already resolved in world millimeters, +Z up. */
56
- declare function createCableMeshes({ definition, path, radialSegments, }: {
56
+ declare function createCableMeshes({ definition, path, radialSegments, startPin1Side, endPin1Side, }: {
57
57
  definition: CableGeometryDefinition;
58
58
  path: CablePoint[];
59
59
  radialSegments?: number;
60
+ /** Directions from connector center toward pin 1 (local -X), in circuit-world XYZ (+Z up), no translation. */
61
+ startPin1Side?: CablePoint;
62
+ endPin1Side?: CablePoint;
60
63
  }): CableMesh[];
61
64
 
62
65
  export { type CableColor, type CableConnectorSpec, type CableGeometryDefinition, type CableMesh, type CablePoint, createCableMeshes };
package/dist/cables.js CHANGED
@@ -46,7 +46,10 @@ function normalize(point) {
46
46
  );
47
47
  return scale(point, 1 / length);
48
48
  }
49
- function createCablePathFrames(path) {
49
+ function createCablePathFrames(path, {
50
+ startPin1Side,
51
+ endPin1Side
52
+ } = {}) {
50
53
  if (path.length < 2 || path.some((point) => point.length !== 3 || !point.every(Number.isFinite))) {
51
54
  throw new Error("Cable path needs at least two finite 3D points");
52
55
  }
@@ -55,8 +58,18 @@ function createCablePathFrames(path) {
55
58
  (_, index) => index === 0 ? segments[0] : index === path.length - 1 ? segments.at(-1) : normalize(add(segments[index - 1], segments[index]))
56
59
  );
57
60
  const initialUp = Math.abs(tangents[0][2]) > 0.95 ? [0, 1, 0] : [0, 0, 1];
58
- let normal = normalize(cross(initialUp, tangents[0]));
59
- return tangents.map((tangent, index) => {
61
+ const endpointNormal = (pin1Side, tangent) => {
62
+ if (pin1Side.length !== 3 || !pin1Side.every(Number.isFinite) || Math.hypot(...pin1Side) < 1e-10)
63
+ throw new Error("Connector pin 1 side must be a finite nonzero vector");
64
+ const normal2 = scale(normalize(pin1Side), -1);
65
+ if (Math.abs(dot(normal2, tangent)) > 1e-5)
66
+ throw new Error(
67
+ "Connector pin 1 side must be perpendicular to its path tangent"
68
+ );
69
+ return normalize(subtract(normal2, scale(tangent, dot(normal2, tangent))));
70
+ };
71
+ let normal = startPin1Side ? endpointNormal(startPin1Side, tangents[0]) : normalize(cross(initialUp, tangents[0]));
72
+ const frames = tangents.map((tangent, index) => {
60
73
  if (index > 0) {
61
74
  const previousTangent = tangents[index - 1];
62
75
  const axis = cross(previousTangent, tangent);
@@ -79,6 +92,32 @@ function createCablePathFrames(path) {
79
92
  binormal: normalize(cross(tangent, normal))
80
93
  };
81
94
  });
95
+ if (!endPin1Side) return frames;
96
+ const last = frames.at(-1);
97
+ const endNormal = endpointNormal(endPin1Side, last.tangent);
98
+ const twist = Math.atan2(
99
+ dot(last.tangent, cross(last.normal, endNormal)),
100
+ dot(last.normal, endNormal)
101
+ );
102
+ const distances = [0];
103
+ for (let index = 1; index < path.length; index++)
104
+ distances.push(
105
+ distances[index - 1] + Math.hypot(...subtract(path[index], path[index - 1]))
106
+ );
107
+ return frames.map((frame, index) => {
108
+ const angle = twist * (startPin1Side ? distances[index] / distances.at(-1) : 1);
109
+ const normal2 = normalize(
110
+ add(
111
+ scale(frame.normal, Math.cos(angle)),
112
+ scale(frame.binormal, Math.sin(angle))
113
+ )
114
+ );
115
+ return {
116
+ ...frame,
117
+ normal: normal2,
118
+ binormal: normalize(cross(frame.tangent, normal2))
119
+ };
120
+ });
82
121
  }
83
122
 
84
123
  // lib/cables/geometry-to-mesh.ts
@@ -655,12 +694,17 @@ function validateCableDefinition(definition) {
655
694
  function createCableMeshes({
656
695
  definition,
657
696
  path,
658
- radialSegments = 24
697
+ radialSegments = 24,
698
+ startPin1Side,
699
+ endPin1Side
659
700
  }) {
660
701
  validateCableDefinition(definition);
661
702
  if (!Number.isInteger(radialSegments) || radialSegments < 8 || radialSegments > 128)
662
703
  throw new Error("radialSegments must be an integer from 8 to 128");
663
- const frames = createCablePathFrames(path);
704
+ const frames = createCablePathFrames(path, {
705
+ startPin1Side,
706
+ endPin1Side
707
+ });
664
708
  const crossSection = definition.crossSection;
665
709
  const jacketDiameter = crossSection.kind === "round_jacket" ? crossSection.diameter : void 0;
666
710
  const meshes = crossSection.kind === "round_jacket" ? [
@@ -1 +1 @@
1
- {"version":3,"sources":["../lib/cables/bullet-meshes.ts","../lib/materials.ts","../lib/cables/geometry-to-mesh.ts","../lib/cables/path-frames.ts","../lib/cables/connector-meshes.ts","../lib/cables/sweep-round-cable.ts","../lib/cables/create-cable-meshes.ts"],"sourcesContent":["import jscad from \"@jscad/modeling\"\nimport { componentMaterials } from \"../materials\"\nimport { geometryToCableMesh } from \"./geometry-to-mesh\"\nimport type { CableConnectorSpec, CableMesh } from \"./types\"\n\n/** Right-handed connector-local mm: mating tip/mouth at z=0, +Z to wire exit.\n * Female socket is hollow; male contact has a rounded tip and spring slots.\n */\nexport function createBulletMeshes(\n connector: Extract<\n CableConnectorSpec,\n { kind: \"bullet_male\" | \"bullet_female\" }\n >,\n): CableMesh[] {\n const { cylinder, sphere, cuboid } = jscad.primitives\n const { subtract, union } = jscad.booleans\n const { diameter, contactDepth, bodyDepth, kind } = connector\n const bodyWidth = connector.bodyHeight\n const radius = diameter / 2\n let contact =\n kind === \"bullet_male\"\n ? union(\n sphere({ radius, center: [0, 0, radius], segments: 32 }),\n cylinder({\n radius,\n height: contactDepth - radius,\n center: [0, 0, (contactDepth + radius) / 2],\n segments: 32,\n }),\n )\n : subtract(\n cylinder({\n radius: bodyWidth / 2,\n height: contactDepth,\n center: [0, 0, contactDepth / 2],\n segments: 32,\n }),\n cylinder({\n radius,\n height: contactDepth - diameter / 4 + 0.1,\n center: [0, 0, (contactDepth - diameter / 4 - 0.1) / 2],\n segments: 32,\n }),\n )\n if (kind === \"bullet_male\") {\n contact = subtract(\n contact,\n cuboid({\n size: [diameter + 0.2, diameter * 0.08, contactDepth * 0.65],\n center: [0, 0, contactDepth * 0.45],\n }),\n cuboid({\n size: [diameter * 0.08, diameter + 0.2, contactDepth * 0.65],\n center: [0, 0, contactDepth * 0.45],\n }),\n )\n }\n const cupDepth = bodyDepth - contactDepth\n const solderCup = subtract(\n cylinder({\n radius: bodyWidth / 2,\n height: cupDepth,\n center: [0, 0, contactDepth + cupDepth / 2],\n segments: 32,\n }),\n cylinder({\n radius: radius * 0.75,\n height: cupDepth * 0.8 + 0.1,\n center: [0, 0, bodyDepth - cupDepth * 0.4 + 0.05],\n segments: 32,\n }),\n )\n const contactMeshes = [\n geometryToCableMesh({\n geometry: contact,\n material: componentMaterials.goldContact,\n color: [0.83, 0.64, 0.22, 1],\n name: kind === \"bullet_male\" ? \"bullet-pin\" : \"bullet-socket\",\n }),\n geometryToCableMesh({\n geometry: solderCup,\n material: componentMaterials.goldContact,\n color: [0.83, 0.64, 0.22, 1],\n name: \"solder-cup\",\n }),\n ]\n const pinCount = connector.pinCount ?? 1\n return Array.from({ length: pinCount }, (_, index) => {\n const offset = (index - (pinCount - 1) / 2) * (connector.pitch ?? bodyWidth)\n return contactMeshes.map((mesh) => ({\n ...mesh,\n name: pinCount === 1 ? mesh.name : `${mesh.name}-${index + 1}`,\n // Local +X is the cable frame's normal, paired with sweepRoundCable.offset.\n positions: mesh.positions.map((coordinate, coordinateIndex) =>\n coordinateIndex % 3 === 0 ? coordinate + offset : coordinate,\n ),\n }))\n }).flat()\n}\n","/** Approximate visual finishes, not measured optical properties. */\nexport const componentMaterials = {\n moldedPlastic: { metalness: 0, roughness: 0.7 },\n rubber: { metalness: 0, roughness: 0.9 },\n sleeve: { metalness: 0, roughness: 0.45 },\n tinnedLead: { metalness: 0.8, roughness: 0.55 },\n goldContact: { metalness: 1, roughness: 0.25 },\n copper: { metalness: 1, roughness: 0.35 },\n brushedMetal: { metalness: 1, roughness: 0.4 },\n steel: { metalness: 1, roughness: 0.25 },\n} as const\n","import jscad from \"@jscad/modeling\"\nimport type { Geom3 } from \"@jscad/modeling/src/geometries/geom3\"\nimport type { CableMesh, CableColor, CableFrame, CablePoint } from \"./types\"\nimport { add, scale } from \"./path-frames\"\n\ntype VertexKey = string\n\nexport function geometryToCableMesh({\n geometry,\n color,\n name,\n material,\n}: {\n geometry: Geom3\n color: CableColor\n name: string\n material?: CableMesh[\"material\"]\n}): CableMesh {\n const triangles = jscad.geometries.geom3.toPolygons(geometry)\n const positions: number[] = []\n const indices: number[] = []\n const vertices = new Map<VertexKey, number>()\n for (const triangle of triangles) {\n const polygonIndices: number[] = []\n for (const point of triangle.vertices) {\n const key = point.map((coordinate) => coordinate.toFixed(8)).join(\",\")\n let index = vertices.get(key)\n if (index === undefined) {\n index = positions.length / 3\n positions.push(...point)\n vertices.set(key, index)\n }\n polygonIndices.push(index)\n }\n // JSCAD CSG polygons are convex, so a fan preserves their outward winding.\n for (let side = 1; side < polygonIndices.length - 1; side++) {\n indices.push(\n polygonIndices[0]!,\n polygonIndices[side]!,\n polygonIndices[side + 1]!,\n )\n }\n }\n return { name, positions, indices, color, material, smooth: false }\n}\n\nexport function placeConnectorMesh({\n mesh,\n frame,\n wireExitDepth,\n isEnd,\n}: {\n mesh: CableMesh\n frame: CableFrame\n wireExitDepth: number\n isEnd: boolean\n}): CableMesh {\n const tangent = scale(frame.tangent, isEnd ? -1 : 1)\n const binormal: CablePoint = isEnd\n ? scale(frame.binormal, -1)\n : frame.binormal\n const origin = add(frame.point, scale(tangent, -wireExitDepth))\n const positions: number[] = []\n for (let index = 0; index < mesh.positions.length; index += 3) {\n positions.push(\n ...add(\n origin,\n add(\n add(\n scale(frame.normal, mesh.positions[index]!),\n scale(binormal, mesh.positions[index + 1]!),\n ),\n scale(tangent, mesh.positions[index + 2]!),\n ),\n ),\n )\n }\n return { ...mesh, positions }\n}\n","import type { CableFrame, CablePoint } from \"./types\"\n\nexport const add = (a: CablePoint, b: CablePoint): CablePoint => [\n a[0] + b[0],\n a[1] + b[1],\n a[2] + b[2],\n]\nexport const subtract = (a: CablePoint, b: CablePoint): CablePoint => [\n a[0] - b[0],\n a[1] - b[1],\n a[2] - b[2],\n]\nexport const scale = (point: CablePoint, factor: number): CablePoint => [\n point[0] * factor,\n point[1] * factor,\n point[2] * factor,\n]\nexport const dot = (a: CablePoint, b: CablePoint) =>\n a[0] * b[0] + a[1] * b[1] + a[2] * b[2]\nexport const cross = (a: CablePoint, b: CablePoint): CablePoint => [\n a[1] * b[2] - a[2] * b[1],\n a[2] * b[0] - a[0] * b[2],\n a[0] * b[1] - a[1] * b[0],\n]\nexport function normalize(point: CablePoint): CablePoint {\n const length = Math.hypot(...point)\n if (length < 1e-10)\n throw new Error(\n \"Cable path must not contain coincident points or a reversing tangent\",\n )\n return scale(point, 1 / length)\n}\n\n/** Parallel transport avoids a wire bundle flipping when its tangent crosses an axis. */\nexport function createCablePathFrames(path: CablePoint[]): CableFrame[] {\n if (\n path.length < 2 ||\n path.some((point) => point.length !== 3 || !point.every(Number.isFinite))\n ) {\n throw new Error(\"Cable path needs at least two finite 3D points\")\n }\n const segments = path\n .slice(1)\n .map((point, index) => normalize(subtract(point, path[index]!)))\n const tangents = path.map((_, index) =>\n index === 0\n ? segments[0]!\n : index === path.length - 1\n ? segments.at(-1)!\n : normalize(add(segments[index - 1]!, segments[index]!)),\n )\n const initialUp: CablePoint =\n Math.abs(tangents[0]![2]) > 0.95 ? [0, 1, 0] : [0, 0, 1]\n let normal = normalize(cross(initialUp, tangents[0]!))\n return tangents.map((tangent, index) => {\n if (index > 0) {\n const previousTangent = tangents[index - 1]!\n const axis = cross(previousTangent, tangent)\n const sine = Math.hypot(...axis)\n const cosine = Math.max(-1, Math.min(1, dot(previousTangent, tangent)))\n if (sine > 1e-10) {\n const unitAxis = scale(axis, 1 / sine)\n normal = normalize(\n add(\n add(scale(normal, cosine), scale(cross(unitAxis, normal), sine)),\n scale(unitAxis, dot(unitAxis, normal) * (1 - cosine)),\n ),\n )\n }\n }\n return {\n point: path[index]!,\n tangent,\n normal,\n binormal: normalize(cross(tangent, normal)),\n }\n })\n}\n","import { createBulletMeshes } from \"./bullet-meshes\"\nimport { componentMaterials } from \"../materials\"\nimport jscad from \"@jscad/modeling\"\nimport { geometryToCableMesh } from \"./geometry-to-mesh\"\nimport type {\n CableColor,\n CableConnectorSpec,\n CableMesh,\n CablePoint,\n} from \"./types\"\n\nconst { cuboid, roundedCuboid, cylinder, roundedRectangle, polygon, sphere } =\n jscad.primitives\nconst { extrudeLinear } = jscad.extrusions\nconst { translate, rotateY } = jscad.transforms\nconst { subtract, union } = jscad.booleans\nconst plastic: CableColor = [0.055, 0.07, 0.09, 1]\nconst housing: CableColor = [0.86, 0.84, 0.75, 1]\nconst metal: CableColor = [0.6, 0.64, 0.7, 1]\nconst brass: CableColor = [0.66, 0.46, 0.18, 1]\n\nexport function connectorWireExitDepth(connector: CableConnectorSpec): number {\n if (connector.kind === \"usb_c_plug\")\n return connector.shellDepth + connector.bodyDepth\n if (connector.kind === \"nema_5_15p\") return 19.05 + connector.bodyDepth\n return connector.bodyDepth\n}\n\nfunction createJstMeshes(\n connector: Extract<\n CableConnectorSpec,\n { kind: \"jst_sh_housing\" | \"jst_ph_housing\" }\n >,\n): CableMesh[] {\n const {\n bodyWidth: width,\n bodyHeight: height,\n bodyDepth: depth,\n pinCount,\n pitch,\n } = connector\n const opening = pitch === 1 ? 0.55 : 1.05\n const holes = Array.from({ length: pinCount }, (_, index) => {\n const x = (index - (pinCount - 1) / 2) * pitch\n return cuboid({\n size: [opening, opening * 1.35, depth - 0.6],\n center: [x, 0, (depth - 0.6) / 2 - 0.02],\n })\n })\n const backHoles = Array.from({ length: pinCount }, (_, index) =>\n cylinder({\n radius: pitch * 0.34,\n height: 1.3,\n segments: 16,\n center: [(index - (pinCount - 1) / 2) * pitch, 0, depth - 0.5],\n }),\n )\n const latchCut = cuboid({\n size: [width * 0.45, 0.5, depth * 0.5],\n center: [0, height / 2, depth * 0.65],\n })\n const body = subtract(\n roundedCuboid({\n size: [width, height, depth],\n center: [0, 0, depth / 2],\n roundRadius: 0.1,\n segments: 8,\n }),\n ...holes,\n ...backHoles,\n latchCut,\n ...Array.from({ length: pinCount }, (_, index) =>\n cuboid({\n size: [opening * 0.8, height * 0.7, depth * 0.24],\n center: [(index - (pinCount - 1) / 2) * pitch, height / 2, depth * 0.7],\n }),\n ),\n )\n const contacts = Array.from({ length: pinCount }, (_, index) => {\n const x = (index - (pinCount - 1) / 2) * pitch\n return geometryToCableMesh({\n material: componentMaterials.goldContact,\n name: `contact-${index + 1}`,\n color: metal,\n geometry: subtract(\n cuboid({\n size: [opening * 0.92, opening * 1.25, depth * 0.65],\n center: [x, 0, depth * 0.45],\n }),\n cuboid({\n size: [\n opening * 0.92 - 0.12,\n opening * 1.25 - 0.12,\n depth * 0.65 + 0.2,\n ],\n center: [x, 0, depth * 0.45],\n }),\n ),\n })\n })\n return [\n geometryToCableMesh({ geometry: body, color: housing, name: \"housing\" }),\n ...contacts,\n ]\n}\n\nfunction createUsbMeshes(\n connector: Extract<CableConnectorSpec, { kind: \"usb_c_plug\" }>,\n): CableMesh[] {\n const {\n shellWidth,\n shellHeight,\n shellDepth,\n bodyWidth,\n bodyHeight,\n bodyDepth,\n } = connector\n const shell = subtract(\n extrudeLinear(\n { height: shellDepth },\n roundedRectangle({\n size: [shellWidth, shellHeight],\n roundRadius: shellHeight / 2 - 0.02,\n segments: 32,\n }),\n ),\n translate(\n [0, 0, -0.1],\n extrudeLinear(\n { height: shellDepth + 0.2 },\n roundedRectangle({\n size: [shellWidth - 0.4, shellHeight - 0.4],\n roundRadius: (shellHeight - 0.4) / 2 - 0.02,\n segments: 32,\n }),\n ),\n ),\n )\n const liner = subtract(\n extrudeLinear(\n { height: shellDepth },\n roundedRectangle({\n size: [shellWidth - 0.41, shellHeight - 0.41],\n roundRadius: 0.85,\n segments: 32,\n }),\n ),\n translate(\n [0, 0, -0.1],\n extrudeLinear(\n { height: shellDepth - 0.3 },\n roundedRectangle({\n size: [shellWidth - 0.8, shellHeight - 0.8],\n roundRadius: 0.65,\n segments: 32,\n }),\n ),\n ),\n )\n const body = roundedCuboid({\n size: [bodyWidth, bodyHeight, bodyDepth],\n center: [0, 0, shellDepth + bodyDepth / 2],\n roundRadius: Math.min(1.3, bodyHeight / 4),\n segments: 16,\n })\n const contacts = Array.from({ length: 24 }, (_, index) =>\n cuboid({\n size: [0.22, 0.08, 3.5],\n center: [((index % 12) - 5.5) * 0.5, index < 12 ? 0.77 : -0.77, 2.6],\n }),\n )\n return [\n geometryToCableMesh({ geometry: body, color: plastic, name: \"overmold\" }),\n geometryToCableMesh({\n geometry: shell,\n color: metal,\n material: componentMaterials.brushedMetal,\n name: \"shell\",\n }),\n geometryToCableMesh({\n geometry: liner,\n color: [0.025, 0.026, 0.03, 1],\n name: \"liner\",\n }),\n ...contacts.map((geometry, index) =>\n geometryToCableMesh({\n geometry,\n color: brass,\n material: componentMaterials.goldContact,\n name: `contact-${index + 1}`,\n }),\n ),\n ]\n}\n\nfunction createMainsMeshes(connector: CableConnectorSpec): CableMesh[] {\n const { bodyWidth, bodyHeight, bodyDepth, kind } = connector\n const faceDepth = kind === \"nema_5_15p\" ? 19.05 : 0\n let body = roundedCuboid({\n size: [bodyWidth, bodyHeight, bodyDepth],\n center: [0, 0, faceDepth + bodyDepth / 2],\n roundRadius: 2,\n segments: 16,\n })\n if (kind === \"nema_5_15p\") {\n const blades = [-6.35, 6.35].map((x) => {\n const blade = cuboid({\n size: [1.524, 6.35, 15.875],\n center: [x, 2.7, 19.05 - 15.875 / 2],\n })\n const hole = translate(\n [x, 2.7, 7.3],\n rotateY(\n Math.PI / 2,\n cylinder({ radius: 1.1, height: 3, segments: 20 }),\n ),\n )\n return subtract(blade, hole)\n })\n const ground = union(\n cylinder({\n radius: 2.38125,\n height: 19.05 - 2.38125,\n center: [0, -9.20625, (19.05 + 2.38125) / 2],\n segments: 32,\n }),\n sphere({ radius: 2.38125, center: [0, -9.20625, 2.38125], segments: 32 }),\n )\n return [\n geometryToCableMesh({\n geometry: body,\n color: plastic,\n name: \"plug-body\",\n }),\n ...blades.map((geometry, index) =>\n geometryToCableMesh({\n geometry,\n color: brass,\n material: componentMaterials.goldContact,\n name: `blade-${index + 1}`,\n }),\n ),\n geometryToCableMesh({\n geometry: ground,\n color: brass,\n material: componentMaterials.goldContact,\n name: \"ground-pin\",\n }),\n ]\n }\n const recess = translate(\n [0, 0, -0.1],\n extrudeLinear(\n { height: 3.2 },\n polygon({\n points: [\n [-9, -6],\n [9, -6],\n [9, 2],\n [5, 6],\n [-5, 6],\n [-9, 2],\n ],\n }),\n ),\n )\n const sockets: CablePoint[] = [\n [-4.4, -1.8, 8],\n [4.4, -1.8, 8],\n [0, 3.1, 8],\n ]\n body = subtract(\n body,\n recess,\n ...sockets.map((center) => cuboid({ size: [2.3, 3.4, 16.2], center })),\n )\n return [\n geometryToCableMesh({\n geometry: body,\n color: plastic,\n name: \"appliance-body\",\n }),\n ...sockets.map(([x, y], index) =>\n geometryToCableMesh({\n geometry: cuboid({ size: [0.15, 2.8, 6], center: [x - 1.05, y, 7.8] }),\n color: brass,\n material: componentMaterials.goldContact,\n name: `socket-contact-${index + 1}`,\n }),\n ),\n ]\n}\n\nexport function createConnectorMeshes({\n connector,\n jacketDiameter,\n}: { connector: CableConnectorSpec; jacketDiameter?: number }): CableMesh[] {\n const meshes =\n connector.kind === \"usb_c_plug\"\n ? createUsbMeshes(connector)\n : connector.kind === \"bullet_male\" || connector.kind === \"bullet_female\"\n ? createBulletMeshes(connector)\n : connector.kind === \"jst_sh_housing\" ||\n connector.kind === \"jst_ph_housing\"\n ? createJstMeshes(connector)\n : createMainsMeshes(connector)\n if (\n jacketDiameter !== undefined &&\n connector.kind !== \"bullet_male\" &&\n connector.kind !== \"bullet_female\"\n ) {\n const exit = connectorWireExitDepth(connector)\n const boot = union(\n cylinder({\n radius: jacketDiameter / 2 + 0.15,\n height: 5,\n center: [0, 0, exit + 2.5],\n segments: 32,\n }),\n ...Array.from({ length: 7 }, (_, index) =>\n cylinder({\n radius: jacketDiameter / 2 + 0.8 - index * 0.06,\n height: 0.28,\n center: [0, 0, exit + 0.4 + index * 0.7],\n segments: 32,\n }),\n ),\n )\n meshes.push(\n geometryToCableMesh({\n geometry: boot,\n color: plastic,\n name: \"strain-relief\",\n }),\n )\n }\n return meshes\n}\n","import { add, scale } from \"./path-frames\"\nimport type { CableFrame, CableMesh, CableColor } from \"./types\"\n\n/** Closed indexed sweep around a supplied centerline; this does not choose a route. */\nexport function sweepRoundCable({\n frames,\n diameter,\n offset = 0,\n radialSegments,\n color,\n name,\n}: {\n frames: CableFrame[]\n diameter: number\n offset?: number\n radialSegments: number\n color: CableColor\n name: string\n}): CableMesh {\n const positions: number[] = []\n const indices: number[] = []\n for (const frame of frames) {\n const center = add(frame.point, scale(frame.normal, offset))\n for (let side = 0; side < radialSegments; side++) {\n const angle = (side * Math.PI * 2) / radialSegments\n positions.push(\n ...add(\n center,\n add(\n scale(frame.normal, (diameter * Math.cos(angle)) / 2),\n scale(frame.binormal, (diameter * Math.sin(angle)) / 2),\n ),\n ),\n )\n }\n }\n for (let ring = 0; ring < frames.length - 1; ring++) {\n for (let side = 0; side < radialSegments; side++) {\n const a = ring * radialSegments + side\n const b = ring * radialSegments + ((side + 1) % radialSegments)\n const c = a + radialSegments\n const d = b + radialSegments\n indices.push(a, b, c, b, d, c)\n }\n }\n const startCenter = positions.length / 3\n positions.push(...add(frames[0]!.point, scale(frames[0]!.normal, offset)))\n const endCenter = positions.length / 3\n positions.push(\n ...add(frames.at(-1)!.point, scale(frames.at(-1)!.normal, offset)),\n )\n const lastRing = (frames.length - 1) * radialSegments\n for (let side = 0; side < radialSegments; side++) {\n const next = (side + 1) % radialSegments\n indices.push(\n startCenter,\n next,\n side,\n endCenter,\n lastRing + side,\n lastRing + next,\n )\n }\n return { name, positions, indices, color, smooth: true }\n}\n","import {\n createConnectorMeshes,\n connectorWireExitDepth,\n} from \"./connector-meshes\"\nimport { placeConnectorMesh } from \"./geometry-to-mesh\"\nimport { createCablePathFrames } from \"./path-frames\"\nimport { sweepRoundCable } from \"./sweep-round-cable\"\nimport type {\n CableColor,\n CableGeometryDefinition,\n CableMesh,\n CablePoint,\n} from \"./types\"\n\nfunction parseCableColor(color: string): CableColor {\n if (!/^#[a-f\\d]{6}$/i.test(color))\n throw new Error(\"Cable colors must be six-digit hex strings\")\n return [\n parseInt(color.slice(1, 3), 16) / 255,\n parseInt(color.slice(3, 5), 16) / 255,\n parseInt(color.slice(5, 7), 16) / 255,\n 1,\n ]\n}\n\nfunction validateCableDefinition(definition: CableGeometryDefinition) {\n for (const connector of [definition.connectorA, definition.connectorB]) {\n const dimensions = [\n connector.bodyWidth,\n connector.bodyHeight,\n connector.bodyDepth,\n ]\n if (connector.kind === \"usb_c_plug\")\n dimensions.push(\n connector.shellWidth,\n connector.shellHeight,\n connector.shellDepth,\n )\n if (\n connector.kind === \"bullet_male\" ||\n connector.kind === \"bullet_female\"\n ) {\n const pinCount = connector.pinCount ?? 1\n const pitch = connector.pitch ?? connector.bodyHeight\n dimensions.push(connector.diameter, connector.contactDepth, pitch)\n if (\n !Number.isInteger(pinCount) ||\n pinCount < 1 ||\n pinCount > 16 ||\n connector.bodyHeight <= connector.diameter ||\n pitch < connector.bodyHeight ||\n Math.abs(\n connector.bodyWidth - (connector.bodyHeight + (pinCount - 1) * pitch),\n ) > 1e-6 ||\n connector.contactDepth >= connector.bodyDepth ||\n connector.contactDepth <= connector.diameter / 2\n )\n throw new Error(\"Bullet contact must fit inside its cylindrical body\")\n if (\n (pinCount === 1 &&\n (definition.crossSection.kind !== \"round_jacket\" ||\n definition.crossSection.diameter > connector.bodyHeight)) ||\n (pinCount > 1 &&\n (definition.crossSection.kind !== \"wire_bundle\" ||\n definition.crossSection.wires.length !== pinCount ||\n definition.crossSection.wirePitch !== pitch ||\n definition.crossSection.wires.some(\n (wire) => wire.diameter > connector.bodyHeight,\n )))\n )\n throw new Error(\n \"Bullet cables require one insulated wire per contact that fits its solder cup\",\n )\n }\n if (\n dimensions.some(\n (dimension) => !Number.isFinite(dimension) || dimension <= 0,\n )\n )\n throw new Error(\"Connector dimensions must be finite and positive\")\n if (\n (connector.kind === \"jst_sh_housing\" ||\n connector.kind === \"jst_ph_housing\") &&\n (!Number.isInteger(connector.pinCount) ||\n connector.pinCount < 2 ||\n !Number.isFinite(connector.pitch) ||\n connector.pitch <= 0)\n )\n throw new Error(\n \"JST connectors need a positive pitch and at least two contacts\",\n )\n }\n const crossSection = definition.crossSection\n const diameters =\n crossSection.kind === \"round_jacket\"\n ? [crossSection.diameter]\n : crossSection.wires.map((wire) => wire.diameter)\n if (\n diameters.length === 0 ||\n diameters.some((diameter) => !Number.isFinite(diameter) || diameter <= 0)\n )\n throw new Error(\"Cable diameters must be finite and positive\")\n if (crossSection.kind === \"wire_bundle\") {\n if (\n !Number.isFinite(crossSection.wirePitch) ||\n crossSection.wires.some((wire) => wire.diameter > crossSection.wirePitch)\n )\n throw new Error(\"Insulated bundle wires must not overlap\")\n for (const connector of [definition.connectorA, definition.connectorB]) {\n if (\n !(\"pinCount\" in connector) ||\n (connector.pinCount ?? 1) !== crossSection.wires.length\n )\n throw new Error(\"Bundle wire count must match connector contact count\")\n }\n }\n}\n\n/** Mesh generation only. Path samples are already resolved in world millimeters, +Z up. */\nexport function createCableMeshes({\n definition,\n path,\n radialSegments = 24,\n}: {\n definition: CableGeometryDefinition\n path: CablePoint[]\n radialSegments?: number\n}): CableMesh[] {\n validateCableDefinition(definition)\n if (\n !Number.isInteger(radialSegments) ||\n radialSegments < 8 ||\n radialSegments > 128\n )\n throw new Error(\"radialSegments must be an integer from 8 to 128\")\n const frames = createCablePathFrames(path)\n const crossSection = definition.crossSection\n const jacketDiameter =\n crossSection.kind === \"round_jacket\" ? crossSection.diameter : undefined\n const meshes =\n crossSection.kind === \"round_jacket\"\n ? [\n sweepRoundCable({\n frames,\n diameter: crossSection.diameter,\n radialSegments,\n color: parseCableColor(crossSection.color),\n name: \"jacket\",\n }),\n ]\n : crossSection.wires.map((wire, index) =>\n sweepRoundCable({\n frames,\n diameter: wire.diameter,\n offset:\n (index - (crossSection.wires.length - 1) / 2) *\n crossSection.wirePitch,\n radialSegments,\n color: parseCableColor(wire.color),\n name: `wire-${index + 1}`,\n }),\n )\n for (const [index, connector] of [\n definition.connectorA,\n definition.connectorB,\n ].entries()) {\n const frame = index === 0 ? frames[0]! : frames.at(-1)!\n const parts = createConnectorMeshes({ connector, jacketDiameter })\n meshes.push(\n ...parts.map((mesh) =>\n placeConnectorMesh({\n mesh: { ...mesh, name: `${index === 0 ? \"A\" : \"B\"}-${mesh.name}` },\n frame,\n isEnd: index === 1,\n wireExitDepth: connectorWireExitDepth(connector),\n }),\n ),\n )\n }\n return meshes\n}\n"],"mappings":"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","names":["jscad","cylinder","sphere","cuboid","jscad","subtract","union","jscad","jscad","subtract"]}
1
+ {"version":3,"sources":["../lib/cables/bullet-meshes.ts","../lib/materials.ts","../lib/cables/geometry-to-mesh.ts","../lib/cables/path-frames.ts","../lib/cables/connector-meshes.ts","../lib/cables/sweep-round-cable.ts","../lib/cables/create-cable-meshes.ts"],"sourcesContent":["import jscad from \"@jscad/modeling\"\nimport { componentMaterials } from \"../materials\"\nimport { geometryToCableMesh } from \"./geometry-to-mesh\"\nimport type { CableConnectorSpec, CableMesh } from \"./types\"\n\n/** Right-handed connector-local mm: mating tip/mouth at z=0, +Z to wire exit.\n * Female socket is hollow; male contact has a rounded tip and spring slots.\n */\nexport function createBulletMeshes(\n connector: Extract<\n CableConnectorSpec,\n { kind: \"bullet_male\" | \"bullet_female\" }\n >,\n): CableMesh[] {\n const { cylinder, sphere, cuboid } = jscad.primitives\n const { subtract, union } = jscad.booleans\n const { diameter, contactDepth, bodyDepth, kind } = connector\n const bodyWidth = connector.bodyHeight\n const radius = diameter / 2\n let contact =\n kind === \"bullet_male\"\n ? union(\n sphere({ radius, center: [0, 0, radius], segments: 32 }),\n cylinder({\n radius,\n height: contactDepth - radius,\n center: [0, 0, (contactDepth + radius) / 2],\n segments: 32,\n }),\n )\n : subtract(\n cylinder({\n radius: bodyWidth / 2,\n height: contactDepth,\n center: [0, 0, contactDepth / 2],\n segments: 32,\n }),\n cylinder({\n radius,\n height: contactDepth - diameter / 4 + 0.1,\n center: [0, 0, (contactDepth - diameter / 4 - 0.1) / 2],\n segments: 32,\n }),\n )\n if (kind === \"bullet_male\") {\n contact = subtract(\n contact,\n cuboid({\n size: [diameter + 0.2, diameter * 0.08, contactDepth * 0.65],\n center: [0, 0, contactDepth * 0.45],\n }),\n cuboid({\n size: [diameter * 0.08, diameter + 0.2, contactDepth * 0.65],\n center: [0, 0, contactDepth * 0.45],\n }),\n )\n }\n const cupDepth = bodyDepth - contactDepth\n const solderCup = subtract(\n cylinder({\n radius: bodyWidth / 2,\n height: cupDepth,\n center: [0, 0, contactDepth + cupDepth / 2],\n segments: 32,\n }),\n cylinder({\n radius: radius * 0.75,\n height: cupDepth * 0.8 + 0.1,\n center: [0, 0, bodyDepth - cupDepth * 0.4 + 0.05],\n segments: 32,\n }),\n )\n const contactMeshes = [\n geometryToCableMesh({\n geometry: contact,\n material: componentMaterials.goldContact,\n color: [0.83, 0.64, 0.22, 1],\n name: kind === \"bullet_male\" ? \"bullet-pin\" : \"bullet-socket\",\n }),\n geometryToCableMesh({\n geometry: solderCup,\n material: componentMaterials.goldContact,\n color: [0.83, 0.64, 0.22, 1],\n name: \"solder-cup\",\n }),\n ]\n const pinCount = connector.pinCount ?? 1\n return Array.from({ length: pinCount }, (_, index) => {\n const offset = (index - (pinCount - 1) / 2) * (connector.pitch ?? bodyWidth)\n return contactMeshes.map((mesh) => ({\n ...mesh,\n name: pinCount === 1 ? mesh.name : `${mesh.name}-${index + 1}`,\n // Local +X is the cable frame's normal, paired with sweepRoundCable.offset.\n positions: mesh.positions.map((coordinate, coordinateIndex) =>\n coordinateIndex % 3 === 0 ? coordinate + offset : coordinate,\n ),\n }))\n }).flat()\n}\n","/** Approximate visual finishes, not measured optical properties. */\nexport const componentMaterials = {\n moldedPlastic: { metalness: 0, roughness: 0.7 },\n rubber: { metalness: 0, roughness: 0.9 },\n sleeve: { metalness: 0, roughness: 0.45 },\n tinnedLead: { metalness: 0.8, roughness: 0.55 },\n goldContact: { metalness: 1, roughness: 0.25 },\n copper: { metalness: 1, roughness: 0.35 },\n brushedMetal: { metalness: 1, roughness: 0.4 },\n steel: { metalness: 1, roughness: 0.25 },\n} as const\n","import jscad from \"@jscad/modeling\"\nimport type { Geom3 } from \"@jscad/modeling/src/geometries/geom3\"\nimport type { CableMesh, CableColor, CableFrame, CablePoint } from \"./types\"\nimport { add, scale } from \"./path-frames\"\n\ntype VertexKey = string\n\nexport function geometryToCableMesh({\n geometry,\n color,\n name,\n material,\n}: {\n geometry: Geom3\n color: CableColor\n name: string\n material?: CableMesh[\"material\"]\n}): CableMesh {\n const triangles = jscad.geometries.geom3.toPolygons(geometry)\n const positions: number[] = []\n const indices: number[] = []\n const vertices = new Map<VertexKey, number>()\n for (const triangle of triangles) {\n const polygonIndices: number[] = []\n for (const point of triangle.vertices) {\n const key = point.map((coordinate) => coordinate.toFixed(8)).join(\",\")\n let index = vertices.get(key)\n if (index === undefined) {\n index = positions.length / 3\n positions.push(...point)\n vertices.set(key, index)\n }\n polygonIndices.push(index)\n }\n // JSCAD CSG polygons are convex, so a fan preserves their outward winding.\n for (let side = 1; side < polygonIndices.length - 1; side++) {\n indices.push(\n polygonIndices[0]!,\n polygonIndices[side]!,\n polygonIndices[side + 1]!,\n )\n }\n }\n return { name, positions, indices, color, material, smooth: false }\n}\n\nexport function placeConnectorMesh({\n mesh,\n frame,\n wireExitDepth,\n isEnd,\n}: {\n mesh: CableMesh\n frame: CableFrame\n wireExitDepth: number\n isEnd: boolean\n}): CableMesh {\n const tangent = scale(frame.tangent, isEnd ? -1 : 1)\n const binormal: CablePoint = isEnd\n ? scale(frame.binormal, -1)\n : frame.binormal\n const origin = add(frame.point, scale(tangent, -wireExitDepth))\n const positions: number[] = []\n for (let index = 0; index < mesh.positions.length; index += 3) {\n positions.push(\n ...add(\n origin,\n add(\n add(\n scale(frame.normal, mesh.positions[index]!),\n scale(binormal, mesh.positions[index + 1]!),\n ),\n scale(tangent, mesh.positions[index + 2]!),\n ),\n ),\n )\n }\n return { ...mesh, positions }\n}\n","import type { CableFrame, CablePoint } from \"./types\"\n\nexport const add = (a: CablePoint, b: CablePoint): CablePoint => [\n a[0] + b[0],\n a[1] + b[1],\n a[2] + b[2],\n]\nexport const subtract = (a: CablePoint, b: CablePoint): CablePoint => [\n a[0] - b[0],\n a[1] - b[1],\n a[2] - b[2],\n]\nexport const scale = (point: CablePoint, factor: number): CablePoint => [\n point[0] * factor,\n point[1] * factor,\n point[2] * factor,\n]\nexport const dot = (a: CablePoint, b: CablePoint) =>\n a[0] * b[0] + a[1] * b[1] + a[2] * b[2]\nexport const cross = (a: CablePoint, b: CablePoint): CablePoint => [\n a[1] * b[2] - a[2] * b[1],\n a[2] * b[0] - a[0] * b[2],\n a[0] * b[1] - a[1] * b[0],\n]\nexport function normalize(point: CablePoint): CablePoint {\n const length = Math.hypot(...point)\n if (length < 1e-10)\n throw new Error(\n \"Cable path must not contain coincident points or a reversing tangent\",\n )\n return scale(point, 1 / length)\n}\n\n/** Pin 1 sides point from the connector center toward its first contact\n * (connector-local -X), expressed as directions (no\n * translation) in right-handed world XYZ, +Z up. Path points are mm in that\n * same frame. Parallel transport preserves legacy roll when no directions\n * are supplied; two constrained ends distribute twist by path arc length.\n */\nexport function createCablePathFrames(\n path: CablePoint[],\n {\n startPin1Side,\n endPin1Side,\n }: {\n startPin1Side?: CablePoint\n endPin1Side?: CablePoint\n } = {},\n): CableFrame[] {\n if (\n path.length < 2 ||\n path.some((point) => point.length !== 3 || !point.every(Number.isFinite))\n ) {\n throw new Error(\"Cable path needs at least two finite 3D points\")\n }\n const segments = path\n .slice(1)\n .map((point, index) => normalize(subtract(point, path[index]!)))\n const tangents = path.map((_, index) =>\n index === 0\n ? segments[0]!\n : index === path.length - 1\n ? segments.at(-1)!\n : normalize(add(segments[index - 1]!, segments[index]!)),\n )\n const initialUp: CablePoint =\n Math.abs(tangents[0]![2]) > 0.95 ? [0, 1, 0] : [0, 0, 1]\n const endpointNormal = (pin1Side: CablePoint, tangent: CablePoint) => {\n if (\n pin1Side.length !== 3 ||\n !pin1Side.every(Number.isFinite) ||\n Math.hypot(...pin1Side) < 1e-10\n )\n throw new Error(\"Connector pin 1 side must be a finite nonzero vector\")\n const normal = scale(normalize(pin1Side), -1)\n if (Math.abs(dot(normal, tangent)) > 1e-5)\n throw new Error(\n \"Connector pin 1 side must be perpendicular to its path tangent\",\n )\n return normalize(subtract(normal, scale(tangent, dot(normal, tangent))))\n }\n let normal = startPin1Side\n ? endpointNormal(startPin1Side, tangents[0]!)\n : normalize(cross(initialUp, tangents[0]!))\n const frames = tangents.map((tangent, index) => {\n if (index > 0) {\n const previousTangent = tangents[index - 1]!\n const axis = cross(previousTangent, tangent)\n const sine = Math.hypot(...axis)\n const cosine = Math.max(-1, Math.min(1, dot(previousTangent, tangent)))\n if (sine > 1e-10) {\n const unitAxis = scale(axis, 1 / sine)\n normal = normalize(\n add(\n add(scale(normal, cosine), scale(cross(unitAxis, normal), sine)),\n scale(unitAxis, dot(unitAxis, normal) * (1 - cosine)),\n ),\n )\n }\n }\n return {\n point: path[index]!,\n tangent,\n normal,\n binormal: normalize(cross(tangent, normal)),\n }\n })\n if (!endPin1Side) return frames\n const last = frames.at(-1)!\n const endNormal = endpointNormal(endPin1Side, last.tangent)\n const twist = Math.atan2(\n dot(last.tangent, cross(last.normal, endNormal)),\n dot(last.normal, endNormal),\n )\n const distances = [0]\n for (let index = 1; index < path.length; index++)\n distances.push(\n distances[index - 1]! +\n Math.hypot(...subtract(path[index]!, path[index - 1]!)),\n )\n return frames.map((frame, index) => {\n const angle =\n twist * (startPin1Side ? distances[index]! / distances.at(-1)! : 1)\n const normal = normalize(\n add(\n scale(frame.normal, Math.cos(angle)),\n scale(frame.binormal, Math.sin(angle)),\n ),\n )\n return {\n ...frame,\n normal,\n binormal: normalize(cross(frame.tangent, normal)),\n }\n })\n}\n","import { createBulletMeshes } from \"./bullet-meshes\"\nimport { componentMaterials } from \"../materials\"\nimport jscad from \"@jscad/modeling\"\nimport { geometryToCableMesh } from \"./geometry-to-mesh\"\nimport type {\n CableColor,\n CableConnectorSpec,\n CableMesh,\n CablePoint,\n} from \"./types\"\n\nconst { cuboid, roundedCuboid, cylinder, roundedRectangle, polygon, sphere } =\n jscad.primitives\nconst { extrudeLinear } = jscad.extrusions\nconst { translate, rotateY } = jscad.transforms\nconst { subtract, union } = jscad.booleans\nconst plastic: CableColor = [0.055, 0.07, 0.09, 1]\nconst housing: CableColor = [0.86, 0.84, 0.75, 1]\nconst metal: CableColor = [0.6, 0.64, 0.7, 1]\nconst brass: CableColor = [0.66, 0.46, 0.18, 1]\n\nexport function connectorWireExitDepth(connector: CableConnectorSpec): number {\n if (connector.kind === \"usb_c_plug\")\n return connector.shellDepth + connector.bodyDepth\n if (connector.kind === \"nema_5_15p\") return 19.05 + connector.bodyDepth\n return connector.bodyDepth\n}\n\nfunction createJstMeshes(\n connector: Extract<\n CableConnectorSpec,\n { kind: \"jst_sh_housing\" | \"jst_ph_housing\" }\n >,\n): CableMesh[] {\n const {\n bodyWidth: width,\n bodyHeight: height,\n bodyDepth: depth,\n pinCount,\n pitch,\n } = connector\n const opening = pitch === 1 ? 0.55 : 1.05\n const holes = Array.from({ length: pinCount }, (_, index) => {\n const x = (index - (pinCount - 1) / 2) * pitch\n return cuboid({\n size: [opening, opening * 1.35, depth - 0.6],\n center: [x, 0, (depth - 0.6) / 2 - 0.02],\n })\n })\n const backHoles = Array.from({ length: pinCount }, (_, index) =>\n cylinder({\n radius: pitch * 0.34,\n height: 1.3,\n segments: 16,\n center: [(index - (pinCount - 1) / 2) * pitch, 0, depth - 0.5],\n }),\n )\n const latchCut = cuboid({\n size: [width * 0.45, 0.5, depth * 0.5],\n center: [0, height / 2, depth * 0.65],\n })\n const body = subtract(\n roundedCuboid({\n size: [width, height, depth],\n center: [0, 0, depth / 2],\n roundRadius: 0.1,\n segments: 8,\n }),\n ...holes,\n ...backHoles,\n latchCut,\n ...Array.from({ length: pinCount }, (_, index) =>\n cuboid({\n size: [opening * 0.8, height * 0.7, depth * 0.24],\n center: [(index - (pinCount - 1) / 2) * pitch, height / 2, depth * 0.7],\n }),\n ),\n )\n const contacts = Array.from({ length: pinCount }, (_, index) => {\n const x = (index - (pinCount - 1) / 2) * pitch\n return geometryToCableMesh({\n material: componentMaterials.goldContact,\n name: `contact-${index + 1}`,\n color: metal,\n geometry: subtract(\n cuboid({\n size: [opening * 0.92, opening * 1.25, depth * 0.65],\n center: [x, 0, depth * 0.45],\n }),\n cuboid({\n size: [\n opening * 0.92 - 0.12,\n opening * 1.25 - 0.12,\n depth * 0.65 + 0.2,\n ],\n center: [x, 0, depth * 0.45],\n }),\n ),\n })\n })\n return [\n geometryToCableMesh({ geometry: body, color: housing, name: \"housing\" }),\n ...contacts,\n ]\n}\n\nfunction createUsbMeshes(\n connector: Extract<CableConnectorSpec, { kind: \"usb_c_plug\" }>,\n): CableMesh[] {\n const {\n shellWidth,\n shellHeight,\n shellDepth,\n bodyWidth,\n bodyHeight,\n bodyDepth,\n } = connector\n const shell = subtract(\n extrudeLinear(\n { height: shellDepth },\n roundedRectangle({\n size: [shellWidth, shellHeight],\n roundRadius: shellHeight / 2 - 0.02,\n segments: 32,\n }),\n ),\n translate(\n [0, 0, -0.1],\n extrudeLinear(\n { height: shellDepth + 0.2 },\n roundedRectangle({\n size: [shellWidth - 0.4, shellHeight - 0.4],\n roundRadius: (shellHeight - 0.4) / 2 - 0.02,\n segments: 32,\n }),\n ),\n ),\n )\n const liner = subtract(\n extrudeLinear(\n { height: shellDepth },\n roundedRectangle({\n size: [shellWidth - 0.41, shellHeight - 0.41],\n roundRadius: 0.85,\n segments: 32,\n }),\n ),\n translate(\n [0, 0, -0.1],\n extrudeLinear(\n { height: shellDepth - 0.3 },\n roundedRectangle({\n size: [shellWidth - 0.8, shellHeight - 0.8],\n roundRadius: 0.65,\n segments: 32,\n }),\n ),\n ),\n )\n const body = roundedCuboid({\n size: [bodyWidth, bodyHeight, bodyDepth],\n center: [0, 0, shellDepth + bodyDepth / 2],\n roundRadius: Math.min(1.3, bodyHeight / 4),\n segments: 16,\n })\n const contacts = Array.from({ length: 24 }, (_, index) =>\n cuboid({\n size: [0.22, 0.08, 3.5],\n center: [((index % 12) - 5.5) * 0.5, index < 12 ? 0.77 : -0.77, 2.6],\n }),\n )\n return [\n geometryToCableMesh({ geometry: body, color: plastic, name: \"overmold\" }),\n geometryToCableMesh({\n geometry: shell,\n color: metal,\n material: componentMaterials.brushedMetal,\n name: \"shell\",\n }),\n geometryToCableMesh({\n geometry: liner,\n color: [0.025, 0.026, 0.03, 1],\n name: \"liner\",\n }),\n ...contacts.map((geometry, index) =>\n geometryToCableMesh({\n geometry,\n color: brass,\n material: componentMaterials.goldContact,\n name: `contact-${index + 1}`,\n }),\n ),\n ]\n}\n\nfunction createMainsMeshes(connector: CableConnectorSpec): CableMesh[] {\n const { bodyWidth, bodyHeight, bodyDepth, kind } = connector\n const faceDepth = kind === \"nema_5_15p\" ? 19.05 : 0\n let body = roundedCuboid({\n size: [bodyWidth, bodyHeight, bodyDepth],\n center: [0, 0, faceDepth + bodyDepth / 2],\n roundRadius: 2,\n segments: 16,\n })\n if (kind === \"nema_5_15p\") {\n const blades = [-6.35, 6.35].map((x) => {\n const blade = cuboid({\n size: [1.524, 6.35, 15.875],\n center: [x, 2.7, 19.05 - 15.875 / 2],\n })\n const hole = translate(\n [x, 2.7, 7.3],\n rotateY(\n Math.PI / 2,\n cylinder({ radius: 1.1, height: 3, segments: 20 }),\n ),\n )\n return subtract(blade, hole)\n })\n const ground = union(\n cylinder({\n radius: 2.38125,\n height: 19.05 - 2.38125,\n center: [0, -9.20625, (19.05 + 2.38125) / 2],\n segments: 32,\n }),\n sphere({ radius: 2.38125, center: [0, -9.20625, 2.38125], segments: 32 }),\n )\n return [\n geometryToCableMesh({\n geometry: body,\n color: plastic,\n name: \"plug-body\",\n }),\n ...blades.map((geometry, index) =>\n geometryToCableMesh({\n geometry,\n color: brass,\n material: componentMaterials.goldContact,\n name: `blade-${index + 1}`,\n }),\n ),\n geometryToCableMesh({\n geometry: ground,\n color: brass,\n material: componentMaterials.goldContact,\n name: \"ground-pin\",\n }),\n ]\n }\n const recess = translate(\n [0, 0, -0.1],\n extrudeLinear(\n { height: 3.2 },\n polygon({\n points: [\n [-9, -6],\n [9, -6],\n [9, 2],\n [5, 6],\n [-5, 6],\n [-9, 2],\n ],\n }),\n ),\n )\n const sockets: CablePoint[] = [\n [-4.4, -1.8, 8],\n [4.4, -1.8, 8],\n [0, 3.1, 8],\n ]\n body = subtract(\n body,\n recess,\n ...sockets.map((center) => cuboid({ size: [2.3, 3.4, 16.2], center })),\n )\n return [\n geometryToCableMesh({\n geometry: body,\n color: plastic,\n name: \"appliance-body\",\n }),\n ...sockets.map(([x, y], index) =>\n geometryToCableMesh({\n geometry: cuboid({ size: [0.15, 2.8, 6], center: [x - 1.05, y, 7.8] }),\n color: brass,\n material: componentMaterials.goldContact,\n name: `socket-contact-${index + 1}`,\n }),\n ),\n ]\n}\n\nexport function createConnectorMeshes({\n connector,\n jacketDiameter,\n}: { connector: CableConnectorSpec; jacketDiameter?: number }): CableMesh[] {\n const meshes =\n connector.kind === \"usb_c_plug\"\n ? createUsbMeshes(connector)\n : connector.kind === \"bullet_male\" || connector.kind === \"bullet_female\"\n ? createBulletMeshes(connector)\n : connector.kind === \"jst_sh_housing\" ||\n connector.kind === \"jst_ph_housing\"\n ? createJstMeshes(connector)\n : createMainsMeshes(connector)\n if (\n jacketDiameter !== undefined &&\n connector.kind !== \"bullet_male\" &&\n connector.kind !== \"bullet_female\"\n ) {\n const exit = connectorWireExitDepth(connector)\n const boot = union(\n cylinder({\n radius: jacketDiameter / 2 + 0.15,\n height: 5,\n center: [0, 0, exit + 2.5],\n segments: 32,\n }),\n ...Array.from({ length: 7 }, (_, index) =>\n cylinder({\n radius: jacketDiameter / 2 + 0.8 - index * 0.06,\n height: 0.28,\n center: [0, 0, exit + 0.4 + index * 0.7],\n segments: 32,\n }),\n ),\n )\n meshes.push(\n geometryToCableMesh({\n geometry: boot,\n color: plastic,\n name: \"strain-relief\",\n }),\n )\n }\n return meshes\n}\n","import { add, scale } from \"./path-frames\"\nimport type { CableFrame, CableMesh, CableColor } from \"./types\"\n\n/** Closed indexed sweep around a supplied centerline; this does not choose a route. */\nexport function sweepRoundCable({\n frames,\n diameter,\n offset = 0,\n radialSegments,\n color,\n name,\n}: {\n frames: CableFrame[]\n diameter: number\n offset?: number\n radialSegments: number\n color: CableColor\n name: string\n}): CableMesh {\n const positions: number[] = []\n const indices: number[] = []\n for (const frame of frames) {\n const center = add(frame.point, scale(frame.normal, offset))\n for (let side = 0; side < radialSegments; side++) {\n const angle = (side * Math.PI * 2) / radialSegments\n positions.push(\n ...add(\n center,\n add(\n scale(frame.normal, (diameter * Math.cos(angle)) / 2),\n scale(frame.binormal, (diameter * Math.sin(angle)) / 2),\n ),\n ),\n )\n }\n }\n for (let ring = 0; ring < frames.length - 1; ring++) {\n for (let side = 0; side < radialSegments; side++) {\n const a = ring * radialSegments + side\n const b = ring * radialSegments + ((side + 1) % radialSegments)\n const c = a + radialSegments\n const d = b + radialSegments\n indices.push(a, b, c, b, d, c)\n }\n }\n const startCenter = positions.length / 3\n positions.push(...add(frames[0]!.point, scale(frames[0]!.normal, offset)))\n const endCenter = positions.length / 3\n positions.push(\n ...add(frames.at(-1)!.point, scale(frames.at(-1)!.normal, offset)),\n )\n const lastRing = (frames.length - 1) * radialSegments\n for (let side = 0; side < radialSegments; side++) {\n const next = (side + 1) % radialSegments\n indices.push(\n startCenter,\n next,\n side,\n endCenter,\n lastRing + side,\n lastRing + next,\n )\n }\n return { name, positions, indices, color, smooth: true }\n}\n","import {\n createConnectorMeshes,\n connectorWireExitDepth,\n} from \"./connector-meshes\"\nimport { placeConnectorMesh } from \"./geometry-to-mesh\"\nimport { createCablePathFrames } from \"./path-frames\"\nimport { sweepRoundCable } from \"./sweep-round-cable\"\nimport type {\n CableColor,\n CableGeometryDefinition,\n CableMesh,\n CablePoint,\n} from \"./types\"\n\nfunction parseCableColor(color: string): CableColor {\n if (!/^#[a-f\\d]{6}$/i.test(color))\n throw new Error(\"Cable colors must be six-digit hex strings\")\n return [\n parseInt(color.slice(1, 3), 16) / 255,\n parseInt(color.slice(3, 5), 16) / 255,\n parseInt(color.slice(5, 7), 16) / 255,\n 1,\n ]\n}\n\nfunction validateCableDefinition(definition: CableGeometryDefinition) {\n for (const connector of [definition.connectorA, definition.connectorB]) {\n const dimensions = [\n connector.bodyWidth,\n connector.bodyHeight,\n connector.bodyDepth,\n ]\n if (connector.kind === \"usb_c_plug\")\n dimensions.push(\n connector.shellWidth,\n connector.shellHeight,\n connector.shellDepth,\n )\n if (\n connector.kind === \"bullet_male\" ||\n connector.kind === \"bullet_female\"\n ) {\n const pinCount = connector.pinCount ?? 1\n const pitch = connector.pitch ?? connector.bodyHeight\n dimensions.push(connector.diameter, connector.contactDepth, pitch)\n if (\n !Number.isInteger(pinCount) ||\n pinCount < 1 ||\n pinCount > 16 ||\n connector.bodyHeight <= connector.diameter ||\n pitch < connector.bodyHeight ||\n Math.abs(\n connector.bodyWidth - (connector.bodyHeight + (pinCount - 1) * pitch),\n ) > 1e-6 ||\n connector.contactDepth >= connector.bodyDepth ||\n connector.contactDepth <= connector.diameter / 2\n )\n throw new Error(\"Bullet contact must fit inside its cylindrical body\")\n if (\n (pinCount === 1 &&\n (definition.crossSection.kind !== \"round_jacket\" ||\n definition.crossSection.diameter > connector.bodyHeight)) ||\n (pinCount > 1 &&\n (definition.crossSection.kind !== \"wire_bundle\" ||\n definition.crossSection.wires.length !== pinCount ||\n definition.crossSection.wirePitch !== pitch ||\n definition.crossSection.wires.some(\n (wire) => wire.diameter > connector.bodyHeight,\n )))\n )\n throw new Error(\n \"Bullet cables require one insulated wire per contact that fits its solder cup\",\n )\n }\n if (\n dimensions.some(\n (dimension) => !Number.isFinite(dimension) || dimension <= 0,\n )\n )\n throw new Error(\"Connector dimensions must be finite and positive\")\n if (\n (connector.kind === \"jst_sh_housing\" ||\n connector.kind === \"jst_ph_housing\") &&\n (!Number.isInteger(connector.pinCount) ||\n connector.pinCount < 2 ||\n !Number.isFinite(connector.pitch) ||\n connector.pitch <= 0)\n )\n throw new Error(\n \"JST connectors need a positive pitch and at least two contacts\",\n )\n }\n const crossSection = definition.crossSection\n const diameters =\n crossSection.kind === \"round_jacket\"\n ? [crossSection.diameter]\n : crossSection.wires.map((wire) => wire.diameter)\n if (\n diameters.length === 0 ||\n diameters.some((diameter) => !Number.isFinite(diameter) || diameter <= 0)\n )\n throw new Error(\"Cable diameters must be finite and positive\")\n if (crossSection.kind === \"wire_bundle\") {\n if (\n !Number.isFinite(crossSection.wirePitch) ||\n crossSection.wires.some((wire) => wire.diameter > crossSection.wirePitch)\n )\n throw new Error(\"Insulated bundle wires must not overlap\")\n for (const connector of [definition.connectorA, definition.connectorB]) {\n if (\n !(\"pinCount\" in connector) ||\n (connector.pinCount ?? 1) !== crossSection.wires.length\n )\n throw new Error(\"Bundle wire count must match connector contact count\")\n }\n }\n}\n\n/** Mesh generation only. Path samples are already resolved in world millimeters, +Z up. */\nexport function createCableMeshes({\n definition,\n path,\n radialSegments = 24,\n startPin1Side,\n endPin1Side,\n}: {\n definition: CableGeometryDefinition\n path: CablePoint[]\n radialSegments?: number\n /** Directions from connector center toward pin 1 (local -X), in circuit-world XYZ (+Z up), no translation. */\n startPin1Side?: CablePoint\n endPin1Side?: CablePoint\n}): CableMesh[] {\n validateCableDefinition(definition)\n if (\n !Number.isInteger(radialSegments) ||\n radialSegments < 8 ||\n radialSegments > 128\n )\n throw new Error(\"radialSegments must be an integer from 8 to 128\")\n const frames = createCablePathFrames(path, {\n startPin1Side,\n endPin1Side,\n })\n const crossSection = definition.crossSection\n const jacketDiameter =\n crossSection.kind === \"round_jacket\" ? crossSection.diameter : undefined\n const meshes =\n crossSection.kind === \"round_jacket\"\n ? [\n sweepRoundCable({\n frames,\n diameter: crossSection.diameter,\n radialSegments,\n color: parseCableColor(crossSection.color),\n name: \"jacket\",\n }),\n ]\n : crossSection.wires.map((wire, index) =>\n sweepRoundCable({\n frames,\n diameter: wire.diameter,\n offset:\n (index - (crossSection.wires.length - 1) / 2) *\n crossSection.wirePitch,\n radialSegments,\n color: parseCableColor(wire.color),\n name: `wire-${index + 1}`,\n }),\n )\n for (const [index, connector] of [\n definition.connectorA,\n definition.connectorB,\n ].entries()) {\n const frame = index === 0 ? frames[0]! : frames.at(-1)!\n const parts = createConnectorMeshes({ connector, jacketDiameter })\n meshes.push(\n ...parts.map((mesh) =>\n placeConnectorMesh({\n mesh: { ...mesh, name: `${index === 0 ? \"A\" : \"B\"}-${mesh.name}` },\n frame,\n isEnd: index === 1,\n wireExitDepth: connectorWireExitDepth(connector),\n }),\n ),\n )\n }\n return meshes\n}\n"],"mappings":"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","names":["jscad","normal","cylinder","sphere","cuboid","jscad","subtract","union","jscad","jscad","subtract"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "jscad-electronics",
3
3
  "type": "module",
4
- "version": "0.0.192",
4
+ "version": "0.0.193",
5
5
  "main": "./dist/index.js",
6
6
  "exports": {
7
7
  ".": {