circuit-json-to-step 0.0.1
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/.claude/settings.local.json +16 -0
- package/CLAUDE.md +10 -0
- package/LICENSE +21 -0
- package/README.md +6 -0
- package/biome.json +100 -0
- package/bunfig.toml +5 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +705 -0
- package/lib/index.ts +545 -0
- package/lib/mesh-generation.ts +333 -0
- package/package.json +29 -0
- package/test/basics/basics01/basics01.json +40 -0
- package/test/basics/basics01/basics01.test.ts +54 -0
- package/test/basics/basics02/basics02.json +19 -0
- package/test/basics/basics02/basics02.test.ts +38 -0
- package/test/basics/basics03/basics03.json +49 -0
- package/test/basics/basics03/basics03.test.ts +38 -0
- package/test/basics/basics04/basics04.json +52 -0
- package/test/basics/basics04/basics04.test.ts +49 -0
- package/test/repros/repro01/repro01.json +2917 -0
- package/test/repros/repro01/repro01.test.ts +48 -0
- package/test/utils/occt/importer.ts +119 -0
- package/tsconfig.json +30 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { writeFileSync } from "node:fs"
|
|
2
|
+
import { test, expect } from "bun:test"
|
|
3
|
+
import { circuitJsonToStep } from "../../../lib/index"
|
|
4
|
+
import { importStepWithOcct } from "../../utils/occt/importer"
|
|
5
|
+
import circuitJson from "./repro01.json"
|
|
6
|
+
|
|
7
|
+
test("basics04: convert circuit json with components to STEP", async () => {
|
|
8
|
+
const stepText = await circuitJsonToStep(circuitJson as any, {
|
|
9
|
+
includeComponents: true,
|
|
10
|
+
productName: "TestPCB_with_components",
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
// Verify STEP format
|
|
14
|
+
expect(stepText).toContain("ISO-10303-21")
|
|
15
|
+
expect(stepText).toContain("END-ISO-10303-21")
|
|
16
|
+
|
|
17
|
+
// Verify product structure
|
|
18
|
+
expect(stepText).toContain("TestPCB_with_components")
|
|
19
|
+
expect(stepText).toContain("MANIFOLD_SOLID_BREP")
|
|
20
|
+
|
|
21
|
+
// Verify holes are created
|
|
22
|
+
expect(stepText).toContain("CIRCLE")
|
|
23
|
+
expect(stepText).toContain("CYLINDRICAL_SURFACE")
|
|
24
|
+
|
|
25
|
+
// Verify we have multiple solids (board + components)
|
|
26
|
+
const solidCount = (stepText.match(/MANIFOLD_SOLID_BREP/g) || []).length
|
|
27
|
+
expect(solidCount).toBeGreaterThanOrEqual(1)
|
|
28
|
+
|
|
29
|
+
// Write STEP file to debug-output
|
|
30
|
+
const outputPath = "debug-output/basics04.step"
|
|
31
|
+
writeFileSync(outputPath, stepText)
|
|
32
|
+
|
|
33
|
+
console.log("✓ STEP file with components generated successfully")
|
|
34
|
+
console.log(` - Solids created: ${solidCount}`)
|
|
35
|
+
console.log(` - STEP text length: ${stepText.length} bytes`)
|
|
36
|
+
console.log(` - Output: ${outputPath}`)
|
|
37
|
+
|
|
38
|
+
// Validate STEP file can be imported with occt-import-js
|
|
39
|
+
const occtResult = await importStepWithOcct(stepText)
|
|
40
|
+
expect(occtResult.success).toBe(true)
|
|
41
|
+
expect(occtResult.meshes.length).toBeGreaterThan(0)
|
|
42
|
+
|
|
43
|
+
const [firstMesh] = occtResult.meshes
|
|
44
|
+
expect(firstMesh.attributes.position.array.length).toBeGreaterThan(0)
|
|
45
|
+
expect(firstMesh.index.array.length).toBeGreaterThan(0)
|
|
46
|
+
|
|
47
|
+
console.log("✓ STEP file successfully validated with occt-import-js")
|
|
48
|
+
}, 30000)
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
export type OcctLinearUnit =
|
|
2
|
+
| "millimeter"
|
|
3
|
+
| "centimeter"
|
|
4
|
+
| "meter"
|
|
5
|
+
| "inch"
|
|
6
|
+
| "foot"
|
|
7
|
+
|
|
8
|
+
export type OcctLinearDeflectionType = "bounding_box_ratio" | "absolute_value"
|
|
9
|
+
|
|
10
|
+
export interface OcctImportParams {
|
|
11
|
+
linearUnit?: OcctLinearUnit
|
|
12
|
+
linearDeflectionType?: OcctLinearDeflectionType
|
|
13
|
+
linearDeflection?: number
|
|
14
|
+
angularDeflection?: number
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface OcctImportNode {
|
|
18
|
+
name: string
|
|
19
|
+
meshes: number[]
|
|
20
|
+
children: OcctImportNode[]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface OcctMeshAttributeData {
|
|
24
|
+
array: number[]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface OcctMeshAttributes {
|
|
28
|
+
position: OcctMeshAttributeData
|
|
29
|
+
normal?: OcctMeshAttributeData
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface OcctMeshFaceRange {
|
|
33
|
+
first: number
|
|
34
|
+
last: number
|
|
35
|
+
color: [number, number, number] | null
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface OcctMesh {
|
|
39
|
+
name: string
|
|
40
|
+
color?: [number, number, number]
|
|
41
|
+
brep_faces: OcctMeshFaceRange[]
|
|
42
|
+
attributes: OcctMeshAttributes
|
|
43
|
+
index: { array: number[] }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface OcctImportResult {
|
|
47
|
+
success: boolean
|
|
48
|
+
root: OcctImportNode
|
|
49
|
+
meshes: OcctMesh[]
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type OcctImport = {
|
|
53
|
+
ReadStepFile(
|
|
54
|
+
content: ArrayBufferView | ArrayBuffer,
|
|
55
|
+
params: OcctImportParams | null,
|
|
56
|
+
): OcctImportResult
|
|
57
|
+
ReadBrepFile(
|
|
58
|
+
content: ArrayBufferView | ArrayBuffer,
|
|
59
|
+
params: OcctImportParams | null,
|
|
60
|
+
): OcctImportResult
|
|
61
|
+
ReadIgesFile(
|
|
62
|
+
content: ArrayBufferView | ArrayBuffer,
|
|
63
|
+
params: OcctImportParams | null,
|
|
64
|
+
): OcctImportResult
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
type OcctImportFactory = () => Promise<OcctImport>
|
|
68
|
+
|
|
69
|
+
let occtInstancePromise: Promise<OcctImport> | undefined
|
|
70
|
+
|
|
71
|
+
async function loadOcct(): Promise<OcctImport> {
|
|
72
|
+
if (!occtInstancePromise) {
|
|
73
|
+
const imported = (await import("occt-import-js")) as any
|
|
74
|
+
const factory = resolveFactory(imported)
|
|
75
|
+
occtInstancePromise = factory()
|
|
76
|
+
}
|
|
77
|
+
return occtInstancePromise
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function resolveFactory(candidate: unknown): OcctImportFactory {
|
|
81
|
+
if (typeof candidate === "function") {
|
|
82
|
+
return candidate as OcctImportFactory
|
|
83
|
+
}
|
|
84
|
+
if (
|
|
85
|
+
candidate &&
|
|
86
|
+
typeof candidate === "object" &&
|
|
87
|
+
"default" in candidate &&
|
|
88
|
+
typeof (candidate as { default: unknown }).default === "function"
|
|
89
|
+
) {
|
|
90
|
+
return (candidate as { default: unknown }).default as OcctImportFactory
|
|
91
|
+
}
|
|
92
|
+
throw new Error("Unable to resolve occt-import-js factory export")
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export type StepInput = string | ArrayBuffer | ArrayBufferView
|
|
96
|
+
|
|
97
|
+
function toUint8Array(input: StepInput): Uint8Array {
|
|
98
|
+
if (typeof input === "string") {
|
|
99
|
+
return new TextEncoder().encode(input)
|
|
100
|
+
}
|
|
101
|
+
if (input instanceof ArrayBuffer) {
|
|
102
|
+
return new Uint8Array(input)
|
|
103
|
+
}
|
|
104
|
+
const view = input as ArrayBufferView
|
|
105
|
+
return new Uint8Array(view.buffer, view.byteOffset, view.byteLength)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export async function importStepWithOcct(
|
|
109
|
+
input: StepInput,
|
|
110
|
+
params: OcctImportParams | null = null,
|
|
111
|
+
): Promise<OcctImportResult> {
|
|
112
|
+
const occt = await loadOcct()
|
|
113
|
+
const data = toUint8Array(input)
|
|
114
|
+
const result = occt.ReadStepFile(data, params)
|
|
115
|
+
if (!result.success) {
|
|
116
|
+
throw new Error("occt-import-js failed to load STEP file")
|
|
117
|
+
}
|
|
118
|
+
return result
|
|
119
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
// Environment setup & latest features
|
|
4
|
+
"lib": ["ESNext"],
|
|
5
|
+
"target": "ESNext",
|
|
6
|
+
"module": "Preserve",
|
|
7
|
+
"moduleDetection": "force",
|
|
8
|
+
"jsx": "react-jsx",
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
|
|
11
|
+
// Bundler mode
|
|
12
|
+
"moduleResolution": "bundler",
|
|
13
|
+
"allowImportingTsExtensions": true,
|
|
14
|
+
"verbatimModuleSyntax": true,
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
|
|
17
|
+
// Best practices
|
|
18
|
+
"strict": true,
|
|
19
|
+
"skipLibCheck": true,
|
|
20
|
+
"noFallthroughCasesInSwitch": true,
|
|
21
|
+
"noUncheckedIndexedAccess": false,
|
|
22
|
+
"noImplicitOverride": true,
|
|
23
|
+
|
|
24
|
+
// Some stricter flags (disabled by default)
|
|
25
|
+
"noUnusedLocals": false,
|
|
26
|
+
"noUnusedParameters": false,
|
|
27
|
+
"noPropertyAccessFromIndexSignature": false
|
|
28
|
+
},
|
|
29
|
+
"exclude": ["circuit-json", "stepts"]
|
|
30
|
+
}
|