dsh-cad 0.2.0

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.
Files changed (113) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +190 -0
  3. package/README.zh-CN.md +173 -0
  4. package/cordis.patch.yml +3 -0
  5. package/lib/b64.js +12 -0
  6. package/lib/cad_connector/builtin-executor.js +55 -0
  7. package/lib/cad_connector/builtin.js +8 -0
  8. package/lib/cad_connector/executor.js +76 -0
  9. package/lib/cad_connector/freecad-executor.js +398 -0
  10. package/lib/cad_connector/freecad.js +8 -0
  11. package/lib/cad_connector/fusion360-executor.js +398 -0
  12. package/lib/cad_connector/fusion360.js +8 -0
  13. package/lib/cad_connector/gstarcad3d.js +8 -0
  14. package/lib/cad_connector/index.js +20 -0
  15. package/lib/cad_connector/onshape.js +8 -0
  16. package/lib/cad_connector/solidworks.js +8 -0
  17. package/lib/cad_connector/types.js +6 -0
  18. package/lib/cad_connector/zw3d.js +8 -0
  19. package/lib/client.js +4117 -0
  20. package/lib/client.js.map +7 -0
  21. package/lib/convert/dcprt.js +38 -0
  22. package/lib/convert/detect.js +22 -0
  23. package/lib/convert/dxf.js +124 -0
  24. package/lib/convert/index.js +70 -0
  25. package/lib/convert/obj.js +106 -0
  26. package/lib/convert/png.js +114 -0
  27. package/lib/convert/step-worker.mjs +61 -0
  28. package/lib/convert/step.js +66 -0
  29. package/lib/convert/stl.js +110 -0
  30. package/lib/convert/svg.js +101 -0
  31. package/lib/demo-bracket.brep +668 -0
  32. package/lib/demo-flange.brep +709 -0
  33. package/lib/demo-shaft.brep +516 -0
  34. package/lib/feature_script/dc_asm.js +17 -0
  35. package/lib/feature_script/dc_engineering.js +19 -0
  36. package/lib/feature_script/dc_prt.js +21 -0
  37. package/lib/feature_script/index.js +7 -0
  38. package/lib/image/profile.js +218 -0
  39. package/lib/index.js +77 -0
  40. package/lib/modeling/assembly.js +63 -0
  41. package/lib/modeling/bin-format.js +80 -0
  42. package/lib/modeling/bin-store.js +67 -0
  43. package/lib/modeling/client.js +117 -0
  44. package/lib/modeling/document.js +55 -0
  45. package/lib/modeling/drawing.js +324 -0
  46. package/lib/modeling/hlr.cjs +328 -0
  47. package/lib/modeling/modeling-worker.cjs +235 -0
  48. package/lib/modeling/occt-adapter.cjs +271 -0
  49. package/lib/routes.js +142 -0
  50. package/lib/store.js +68 -0
  51. package/lib/tools/cad-freecad.js +160 -0
  52. package/lib/tools/cad-fusion.js +138 -0
  53. package/lib/tools/cad-image.js +121 -0
  54. package/lib/tools/cad-info.js +92 -0
  55. package/lib/tools/cad-model.js +816 -0
  56. package/lib/tools/cad-view.js +112 -0
  57. package/lib/tools/util.js +25 -0
  58. package/lib/types/b64.d.ts +8 -0
  59. package/lib/types/cad/builtin.d.ts +3 -0
  60. package/lib/types/cad/freecad.d.ts +3 -0
  61. package/lib/types/cad/fusion360.d.ts +3 -0
  62. package/lib/types/cad/gstarcad3d.d.ts +3 -0
  63. package/lib/types/cad/index.d.ts +8 -0
  64. package/lib/types/cad/onshape.d.ts +3 -0
  65. package/lib/types/cad/solidworks.d.ts +3 -0
  66. package/lib/types/cad/types.d.ts +21 -0
  67. package/lib/types/cad/zw3d.d.ts +3 -0
  68. package/lib/types/cad_connector/builtin-executor.d.ts +9 -0
  69. package/lib/types/cad_connector/builtin.d.ts +3 -0
  70. package/lib/types/cad_connector/executor.d.ts +69 -0
  71. package/lib/types/cad_connector/freecad-executor.d.ts +55 -0
  72. package/lib/types/cad_connector/freecad.d.ts +3 -0
  73. package/lib/types/cad_connector/fusion360-executor.d.ts +11 -0
  74. package/lib/types/cad_connector/fusion360.d.ts +3 -0
  75. package/lib/types/cad_connector/gstarcad3d.d.ts +3 -0
  76. package/lib/types/cad_connector/index.d.ts +8 -0
  77. package/lib/types/cad_connector/onshape.d.ts +3 -0
  78. package/lib/types/cad_connector/solidworks.d.ts +3 -0
  79. package/lib/types/cad_connector/types.d.ts +21 -0
  80. package/lib/types/cad_connector/zw3d.d.ts +3 -0
  81. package/lib/types/convert/dcprt.d.ts +14 -0
  82. package/lib/types/convert/detect.d.ts +7 -0
  83. package/lib/types/convert/dxf.d.ts +3 -0
  84. package/lib/types/convert/index.d.ts +9 -0
  85. package/lib/types/convert/obj.d.ts +7 -0
  86. package/lib/types/convert/png.d.ts +8 -0
  87. package/lib/types/convert/step.d.ts +4 -0
  88. package/lib/types/convert/stl.d.ts +7 -0
  89. package/lib/types/convert/svg.d.ts +8 -0
  90. package/lib/types/feature_script/dc_asm.d.ts +40 -0
  91. package/lib/types/feature_script/dc_engineering.d.ts +55 -0
  92. package/lib/types/feature_script/dc_prt.d.ts +37 -0
  93. package/lib/types/feature_script/index.d.ts +7 -0
  94. package/lib/types/image/profile.d.ts +28 -0
  95. package/lib/types/index.d.ts +18 -0
  96. package/lib/types/modeling/assembly.d.ts +17 -0
  97. package/lib/types/modeling/bin-format.d.ts +42 -0
  98. package/lib/types/modeling/bin-store.d.ts +20 -0
  99. package/lib/types/modeling/client.d.ts +125 -0
  100. package/lib/types/modeling/document.d.ts +26 -0
  101. package/lib/types/modeling/drawing.d.ts +38 -0
  102. package/lib/types/routes.d.ts +27 -0
  103. package/lib/types/store.d.ts +18 -0
  104. package/lib/types/tools/cad-freecad.d.ts +10 -0
  105. package/lib/types/tools/cad-fusion.d.ts +8 -0
  106. package/lib/types/tools/cad-image.d.ts +8 -0
  107. package/lib/types/tools/cad-info.d.ts +6 -0
  108. package/lib/types/tools/cad-model.d.ts +13 -0
  109. package/lib/types/tools/cad-view.d.ts +10 -0
  110. package/lib/types/tools/util.d.ts +4 -0
  111. package/lib/types/types.d.ts +142 -0
  112. package/lib/types.js +25 -0
  113. package/package.json +91 -0
@@ -0,0 +1,110 @@
1
+ import { encodeF32B64, encodeU32B64 } from '../b64.js';
2
+ const BINARY_HEADER_SIZE = 80;
3
+ const BINARY_TRIANGLE_SIZE = 50; // 12 normal + 36 vertices + 2 count
4
+ /** Decide binary vs ASCII by the classic solid-prefix heuristic. */
5
+ function isAscii(buffer) {
6
+ const head = buffer.subarray(0, Math.min(buffer.length, 512)).toString('latin1').trimStart();
7
+ return head.startsWith('solid') && !looksBinary(buffer);
8
+ }
9
+ function looksBinary(buffer) {
10
+ if (buffer.length < BINARY_HEADER_SIZE + 4)
11
+ return true;
12
+ const triangleCount = buffer.readUInt32LE(BINARY_HEADER_SIZE);
13
+ const expected = BINARY_HEADER_SIZE + 4 + triangleCount * BINARY_TRIANGLE_SIZE;
14
+ return buffer.length === expected;
15
+ }
16
+ /** Weld positions by exact float-key to index STL's raw triangle soup. */
17
+ function indexTriangleSoup(triangles, triangleCount, normals) {
18
+ const vertexMap = new Map();
19
+ const positions = [];
20
+ const indices = [];
21
+ const dedupNormals = [];
22
+ for (let triangle = 0; triangle < triangleCount; triangle++) {
23
+ const base = triangle * 9;
24
+ for (let corner = 0; corner < 3; corner++) {
25
+ const v = base + corner * 3;
26
+ const key = `${triangles[v]},${triangles[v + 1]},${triangles[v + 2]}`;
27
+ let index = vertexMap.get(key);
28
+ if (index === undefined) {
29
+ index = positions.length / 3;
30
+ vertexMap.set(key, index);
31
+ positions.push(triangles[v], triangles[v + 1], triangles[v + 2]);
32
+ if (normals !== null) {
33
+ const n = base - (base % 9) + 0; // normal of this triangle (same for 3 corners)
34
+ dedupNormals.push(normals[n], normals[n + 1], normals[n + 2]);
35
+ }
36
+ }
37
+ indices.push(index);
38
+ }
39
+ }
40
+ return {
41
+ positions: Float32Array.from(positions),
42
+ normals: normals === null ? null : Float32Array.from(dedupNormals),
43
+ indices: Uint32Array.from(indices),
44
+ };
45
+ }
46
+ function parseBinary(buffer) {
47
+ const triangleCount = buffer.readUInt32LE(BINARY_HEADER_SIZE);
48
+ const triangles = new Float32Array(triangleCount * 9);
49
+ const normals = new Float32Array(triangleCount * 3);
50
+ let offset = BINARY_HEADER_SIZE + 4;
51
+ for (let triangle = 0; triangle < triangleCount; triangle++) {
52
+ normals[triangle * 3] = buffer.readFloatLE(offset);
53
+ normals[triangle * 3 + 1] = buffer.readFloatLE(offset + 4);
54
+ normals[triangle * 3 + 2] = buffer.readFloatLE(offset + 8);
55
+ offset += 12;
56
+ for (let corner = 0; corner < 9; corner++) {
57
+ triangles[triangle * 9 + corner] = buffer.readFloatLE(offset);
58
+ offset += 4;
59
+ }
60
+ offset += 2; // attribute byte count
61
+ }
62
+ return indexTriangleSoup(triangles, triangleCount, normals);
63
+ }
64
+ /** Parse ASCII STL: `vertex x y z` triplets grouped into facet loops. */
65
+ function parseAscii(text) {
66
+ const vertices = [];
67
+ const normals = [];
68
+ let currentNormal = null;
69
+ let cornersInFacet = 0;
70
+ for (const line of text.split(/\r?\n/)) {
71
+ const trimmed = line.trim();
72
+ if (trimmed === '')
73
+ continue;
74
+ const lower = trimmed.toLowerCase();
75
+ if (lower.startsWith('facet normal')) {
76
+ const parts = lower.split(/\s+/);
77
+ currentNormal = [Number(parts[2]), Number(parts[3]), Number(parts[4])];
78
+ cornersInFacet = 0;
79
+ }
80
+ else if (lower.startsWith('vertex')) {
81
+ const parts = lower.split(/\s+/);
82
+ vertices.push(Number(parts[1]), Number(parts[2]), Number(parts[3]));
83
+ if (cornersInFacet === 0 && currentNormal !== null) {
84
+ normals.push(currentNormal[0], currentNormal[1], currentNormal[2]);
85
+ }
86
+ cornersInFacet++;
87
+ }
88
+ else if (lower.startsWith('endfacet')) {
89
+ // Facets with fewer or more than 3 vertices are malformed; STL requires 3.
90
+ if (cornersInFacet !== 3)
91
+ throw new Error(`malformed ASCII STL facet: expected 3 vertices, found ${cornersInFacet}`);
92
+ }
93
+ }
94
+ const triangleCount = vertices.length / 9;
95
+ if (!Number.isInteger(triangleCount) || triangleCount === 0)
96
+ throw new Error('malformed ASCII STL: no complete facets');
97
+ return indexTriangleSoup(Float32Array.from(vertices), triangleCount, Float32Array.from(normals));
98
+ }
99
+ /** Convert an STL buffer into one indexed CadMesh. */
100
+ export function parseSTL(buffer, name) {
101
+ const mesh = isAscii(buffer) ? parseAscii(buffer.toString('latin1')) : parseBinary(buffer);
102
+ return {
103
+ name,
104
+ positions: encodeF32B64(mesh.positions),
105
+ normals: mesh.normals === null ? undefined : encodeF32B64(mesh.normals),
106
+ indices: encodeU32B64(mesh.indices),
107
+ vertexCount: mesh.positions.length / 3,
108
+ triangleCount: mesh.indices.length / 3,
109
+ };
110
+ }
@@ -0,0 +1,101 @@
1
+ function numberAttribute(tag, name, fallback = 0) {
2
+ const match = tag.match(new RegExp(`${name}\\s*=\\s*"([^"]*)"`));
3
+ if (match === null)
4
+ return fallback;
5
+ const value = Number(match[1]);
6
+ return Number.isFinite(value) ? value : fallback;
7
+ }
8
+ function colorAttribute(tag) {
9
+ const stroke = tag.match(/stroke\s*=\s*"#([0-9a-fA-F]{6})"/);
10
+ if (stroke === null || stroke[1] === 'none')
11
+ return undefined;
12
+ return parseInt(stroke[1], 16);
13
+ }
14
+ /** Extract the renderable entity subset from an SVG document. */
15
+ export function parseSVG(text) {
16
+ const entities = [];
17
+ let minX = Infinity;
18
+ let minY = Infinity;
19
+ let maxX = -Infinity;
20
+ let maxY = -Infinity;
21
+ const track = (x, y) => {
22
+ minX = Math.min(minX, x);
23
+ minY = Math.min(minY, y);
24
+ maxX = Math.max(maxX, x);
25
+ maxY = Math.max(maxY, y);
26
+ };
27
+ // User-space y grows downward in SVG; flip into math orientation.
28
+ const flipY = (text.match(/\by2?\s*=\s*"/) !== null);
29
+ const maybeFlip = (y) => (flipY ? -y : y);
30
+ for (const tag of text.matchAll(/<(line|circle|rect|polyline)\b[^>]*>/gi)) {
31
+ const element = tag[0];
32
+ const kind = tag[1].toLowerCase();
33
+ const color = colorAttribute(element);
34
+ switch (kind) {
35
+ case 'line': {
36
+ const x1 = numberAttribute(element, 'x1');
37
+ const y1 = maybeFlip(numberAttribute(element, 'y1'));
38
+ const x2 = numberAttribute(element, 'x2');
39
+ const y2 = maybeFlip(numberAttribute(element, 'y2'));
40
+ entities.push({ type: 'line', x1, y1, x2, y2, color });
41
+ track(x1, y1);
42
+ track(x2, y2);
43
+ break;
44
+ }
45
+ case 'circle': {
46
+ const cx = numberAttribute(element, 'cx');
47
+ const cy = maybeFlip(numberAttribute(element, 'cy'));
48
+ const r = numberAttribute(element, 'r');
49
+ entities.push({ type: 'circle', cx, cy, r, color });
50
+ track(cx - r, cy - r);
51
+ track(cx + r, cy + r);
52
+ break;
53
+ }
54
+ case 'rect': {
55
+ const x = numberAttribute(element, 'x');
56
+ const y = maybeFlip(numberAttribute(element, 'y'));
57
+ const width = numberAttribute(element, 'width');
58
+ const height = numberAttribute(element, 'height');
59
+ const points = [x, y, x + width, y, x + width, y - height, x, y - height];
60
+ entities.push({ type: 'polyline', points, closed: true, color });
61
+ track(x, y - height);
62
+ track(x + width, y);
63
+ break;
64
+ }
65
+ case 'polyline': {
66
+ const pointsMatch = element.match(/points\s*=\s*"([^"]*)"/);
67
+ if (pointsMatch === null)
68
+ break;
69
+ const points = [];
70
+ for (const pair of pointsMatch[1].trim().split(/\s+/)) {
71
+ const [xs, ys] = pair.split(',');
72
+ const x = Number(xs);
73
+ const y = Number(ys);
74
+ if (Number.isFinite(x) && Number.isFinite(y)) {
75
+ points.push(x, maybeFlip(y));
76
+ track(x, maybeFlip(y));
77
+ }
78
+ }
79
+ if (points.length >= 4)
80
+ entities.push({ type: 'polyline', points, closed: element.includes('polygon'), color });
81
+ break;
82
+ }
83
+ }
84
+ }
85
+ if (!Number.isFinite(minX)) {
86
+ const width = numberAttribute(text.match(/<svg\b[^>]*>/)?.[0] ?? '', 'width', 100);
87
+ const height = numberAttribute(text.match(/<svg\b[^>]*>/)?.[0] ?? '', 'height', 100);
88
+ minX = 0;
89
+ minY = -height;
90
+ maxX = width;
91
+ maxY = 0;
92
+ }
93
+ return {
94
+ kind: '2d',
95
+ format: 'svg',
96
+ entities,
97
+ bounds: { min: { x: minX, y: minY }, max: { x: maxX, y: maxY } },
98
+ layers: [],
99
+ svgText: text,
100
+ };
101
+ }