Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export interface CircuitJsonToStepOptions {
boardThickness?: number
/** Product name (default: "PCB") */
productName?: string
/** Include component meshes (default: false) */
/** Include component meshes (default: true) */
includeComponents?: boolean
/** Include external model meshes from model_*_url fields (default: false). Only applicable when includeComponents is true. */
includeExternalMeshes?: boolean
Expand Down Expand Up @@ -86,6 +86,7 @@ export async function circuitJsonToStep(
const boardWidth = options.boardWidth ?? pcbBoard?.width
const boardHeight = options.boardHeight ?? pcbBoard?.height
const boardThickness = options.boardThickness ?? pcbBoard?.thickness ?? 1.6
const includeComponents = options.includeComponents ?? true
const productName = options.productName ?? "PCB"

// Get board center position (defaults to 0, 0 if not specified)
Expand Down Expand Up @@ -568,7 +569,7 @@ export async function circuitJsonToStep(
let handledComponentIds = new Set<string>()
let handledPcbComponentIds = new Set<string>()

if (options.includeComponents && options.includeExternalMeshes) {
if (includeComponents && options.includeExternalMeshes) {
const mergeResult = await mergeExternalStepModels({
repo,
circuitJson,
Expand All @@ -582,7 +583,7 @@ export async function circuitJsonToStep(

// Generate component mesh fallback if requested
// Only call mesh generation if there are components that need it
if (options.includeComponents) {
if (includeComponents) {
// Build set of pcb_component_ids covered by cad_components with model_step_url
const pcbComponentIdsWithStepUrl = new Set<string>()
for (const item of circuitJson) {
Expand Down
35 changes: 19 additions & 16 deletions lib/mesh-generation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,44 +327,47 @@ export async function generateComponentMeshes(
renderBoardTextures: false,
})

// Extract or generate triangles from component boxes
const allTriangles: GLTFTriangle[] = []
for (const box of scene3d.boxes) {
// Process each component box as a separate STEP solid.
// STEP requires each ManifoldSolidBrep to have a closed, watertight
// boundary — merging triangles from multiple disconnected boxes into
// one ClosedShell produces an invalid solid that viewers silently drop.
for (let i = 0; i < scene3d.boxes.length; i++) {
const box = scene3d.boxes[i]

let boxTriangles: GLTFTriangle[]
if (box.mesh && "triangles" in box.mesh) {
allTriangles.push(...box.mesh.triangles)
boxTriangles = box.mesh.triangles
} else {
// Generate simple box mesh for this component
const boxTriangles = createBoxTriangles(box)
allTriangles.push(...boxTriangles)
boxTriangles = createBoxTriangles(box)
}
}

// Create STEP faces from triangles if we have any
if (allTriangles.length > 0) {
// Transform triangles from GLTF XZ plane (Y=up) to STEP XY plane (Z=up)
const transformedTriangles = allTriangles.map((tri) => ({
if (boxTriangles.length === 0) continue

// Transform from GLTF coordinate system (Y-up) to STEP (Z-up)
const transformedTriangles = boxTriangles.map((tri) => ({
vertices: tri.vertices.map((v) => ({
x: v.x,
y: v.z, // GLTF Z becomes STEP Y
z: v.y, // GLTF Y becomes STEP Z
})),
normal: {
x: tri.normal.x,
y: tri.normal.z, // GLTF Z becomes STEP Y
z: tri.normal.y, // GLTF Y becomes STEP Z
y: tri.normal.z,
z: tri.normal.y,
},
}))

const componentFaces = createStepFacesFromTriangles(
repo,
transformedTriangles as any,
)

// Create closed shell and solid for components
const componentShell = repo.add(
new ClosedShell("", componentFaces as any),
)
const componentName = (box as any).name || `Component_${i + 1}`
const componentSolid = repo.add(
new ManifoldSolidBrep("Components", componentShell),
new ManifoldSolidBrep(componentName, componentShell),
)
solids.push(componentSolid)
}
Expand Down