cyclecad 3.2.1 → 3.5.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.
- package/CLAUDE.md +155 -1
- package/DOCKER-SETUP-VERIFICATION.md +399 -0
- package/DOCKER-TESTING.md +463 -0
- package/FUSION360_MODULES.md +478 -0
- package/FUSION_MODULES_README.md +352 -0
- package/INTEGRATION_SNIPPETS.md +608 -0
- package/KILLER-FEATURES-DELIVERY.md +469 -0
- package/MODULES_SUMMARY.txt +337 -0
- package/QUICK_REFERENCE.txt +298 -0
- package/README-DOCKER-TESTING.txt +438 -0
- package/app/index.html +23 -10
- package/app/js/fusion-help.json +1808 -0
- package/app/js/help-module-v3.js +1096 -0
- package/app/js/killer-features-help.json +395 -0
- package/app/js/killer-features.js +1508 -0
- package/app/js/modules/fusion-assembly.js +842 -0
- package/app/js/modules/fusion-cam.js +785 -0
- package/app/js/modules/fusion-data.js +814 -0
- package/app/js/modules/fusion-drawing.js +844 -0
- package/app/js/modules/fusion-inspection.js +756 -0
- package/app/js/modules/fusion-render.js +774 -0
- package/app/js/modules/fusion-simulation.js +986 -0
- package/app/js/modules/fusion-sketch.js +1044 -0
- package/app/js/modules/fusion-solid.js +1095 -0
- package/app/js/modules/fusion-surface.js +949 -0
- package/app/tests/FUSION_TEST_SUITE.md +266 -0
- package/app/tests/README.md +77 -0
- package/app/tests/TESTING-CHECKLIST.md +177 -0
- package/app/tests/TEST_SUITE_SUMMARY.txt +236 -0
- package/app/tests/brep-live-test.html +848 -0
- package/app/tests/docker-integration-test.html +811 -0
- package/app/tests/fusion-all-tests.html +670 -0
- package/app/tests/fusion-assembly-tests.html +461 -0
- package/app/tests/fusion-cam-tests.html +421 -0
- package/app/tests/fusion-simulation-tests.html +421 -0
- package/app/tests/fusion-sketch-tests.html +613 -0
- package/app/tests/fusion-solid-tests.html +529 -0
- package/app/tests/index.html +453 -0
- package/app/tests/killer-features-test.html +509 -0
- package/app/tests/run-tests.html +874 -0
- package/app/tests/step-import-live-test.html +1115 -0
- package/app/tests/test-agent-v3.html +93 -696
- package/architecture-dashboard.html +1970 -0
- package/docs/API-REFERENCE.md +1423 -0
- package/docs/BREP-LIVE-TEST-GUIDE.md +453 -0
- package/docs/DEVELOPER-GUIDE-v3.md +795 -0
- package/docs/DOCKER-QUICK-TEST.md +376 -0
- package/docs/FUSION-FEATURES-GUIDE.md +2513 -0
- package/docs/FUSION-TUTORIAL.md +1203 -0
- package/docs/INFRASTRUCTURE-GUIDE-INDEX.md +327 -0
- package/docs/KEYBOARD-SHORTCUTS.md +402 -0
- package/docs/KILLER-FEATURES-INTEGRATION.md +412 -0
- package/docs/KILLER-FEATURES-SUMMARY.md +424 -0
- package/docs/KILLER-FEATURES-TUTORIAL.md +784 -0
- package/docs/KILLER-FEATURES.md +562 -0
- package/docs/QUICK-REFERENCE.md +282 -0
- package/docs/README-v3-DOCS.md +274 -0
- package/docs/TUTORIAL-v3.md +1190 -0
- package/docs/architecture-dashboard.html +1970 -0
- package/docs/architecture-v3.html +1038 -0
- package/linkedin-post-v3.md +58 -0
- package/package.json +1 -1
- package/scripts/dev-setup.sh +338 -0
- package/scripts/docker-health-check.sh +159 -0
- package/scripts/integration-test.sh +311 -0
- package/scripts/test-docker.sh +515 -0
|
@@ -0,0 +1,844 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cycleCAD — Fusion 360 Drawing Module
|
|
3
|
+
* Complete 2D technical drawing workspace with views, dimensions, GD&T, and standards compliance.
|
|
4
|
+
*
|
|
5
|
+
* Features:
|
|
6
|
+
* - Paper sizes (A4/A3/A2/A1/Letter/Tabloid)
|
|
7
|
+
* - Base/Projected/Section/Detail/Break Views
|
|
8
|
+
* - Linear/Angular/Radial/Diameter/Ordinate Dimensions
|
|
9
|
+
* - GD&T frames (Flatness, Parallelism, Perpendicularity, Concentricity, etc.)
|
|
10
|
+
* - Surface finish symbols, Hole callouts, Center marks
|
|
11
|
+
* - Customizable title block with company branding
|
|
12
|
+
* - Parts list / BOM table generation
|
|
13
|
+
* - ISO 128 and ANSI Y14.5 compliance
|
|
14
|
+
* - Export to PDF / DXF
|
|
15
|
+
*
|
|
16
|
+
* Version: 1.0.0
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Fusion Drawing Module — Technical drawing workspace
|
|
23
|
+
*/
|
|
24
|
+
class FusionDrawingModule {
|
|
25
|
+
constructor(scene, camera, renderer) {
|
|
26
|
+
this.scene = scene;
|
|
27
|
+
this.camera = camera;
|
|
28
|
+
this.renderer = renderer;
|
|
29
|
+
|
|
30
|
+
// Drawing settings
|
|
31
|
+
this.paperSize = 'A3'; // A4 | A3 | A2 | A1 | Letter | Tabloid
|
|
32
|
+
this.paperDimensions = this.getPaperDimensions();
|
|
33
|
+
this.scale = 1; // Drawing scale
|
|
34
|
+
this.unit = 'mm';
|
|
35
|
+
|
|
36
|
+
// Canvas for 2D drawing (orthographic)
|
|
37
|
+
this.canvas = null;
|
|
38
|
+
this.ctx = null;
|
|
39
|
+
this.drawingCanvas = null;
|
|
40
|
+
|
|
41
|
+
// Views
|
|
42
|
+
this.views = new Map(); // viewId -> view definition
|
|
43
|
+
this.baseView = null;
|
|
44
|
+
|
|
45
|
+
// Dimensions
|
|
46
|
+
this.dimensions = new Map(); // dimId -> dimension definition
|
|
47
|
+
this.gdtFrames = new Map(); // frameId -> GD&T frame definition
|
|
48
|
+
|
|
49
|
+
// Annotations
|
|
50
|
+
this.notes = [];
|
|
51
|
+
this.centerMarks = [];
|
|
52
|
+
this.centerLines = [];
|
|
53
|
+
this.balloons = [];
|
|
54
|
+
|
|
55
|
+
// Title block
|
|
56
|
+
this.titleBlock = {
|
|
57
|
+
company: 'Your Company',
|
|
58
|
+
designer: 'Designer Name',
|
|
59
|
+
date: new Date().toISOString().split('T')[0],
|
|
60
|
+
scale: '1:1',
|
|
61
|
+
material: 'Steel',
|
|
62
|
+
sheetNumber: '1/1',
|
|
63
|
+
revision: 'A',
|
|
64
|
+
documentNumber: '000001'
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// BOM data
|
|
68
|
+
this.bomItems = [];
|
|
69
|
+
this.bomLocation = { x: 20, y: 50 }; // Bottom right corner
|
|
70
|
+
|
|
71
|
+
// Hatch patterns for section views
|
|
72
|
+
this.hatchPatterns = {
|
|
73
|
+
steel: { angle: 45, spacing: 2, color: '#666666' },
|
|
74
|
+
aluminum: { angle: 45, spacing: 2, color: '#aaaaaa' },
|
|
75
|
+
plastic: { angle: 45, spacing: 3, color: '#cccccc' }
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Initialize drawing module UI
|
|
81
|
+
*/
|
|
82
|
+
init() {
|
|
83
|
+
this.setupDrawingCanvas();
|
|
84
|
+
this.setupEventListeners();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Get UI panel for drawing controls
|
|
89
|
+
*/
|
|
90
|
+
getUI() {
|
|
91
|
+
const panel = document.createElement('div');
|
|
92
|
+
panel.className = 'fusion-drawing-panel';
|
|
93
|
+
panel.innerHTML = `
|
|
94
|
+
<style>
|
|
95
|
+
.fusion-drawing-panel {
|
|
96
|
+
padding: 16px;
|
|
97
|
+
font-size: 12px;
|
|
98
|
+
background: var(--bg-secondary);
|
|
99
|
+
color: var(--text-primary);
|
|
100
|
+
border-radius: 4px;
|
|
101
|
+
max-height: 700px;
|
|
102
|
+
overflow-y: auto;
|
|
103
|
+
}
|
|
104
|
+
.fusion-drawing-panel h3 {
|
|
105
|
+
margin: 0 0 12px 0;
|
|
106
|
+
font-size: 14px;
|
|
107
|
+
font-weight: 600;
|
|
108
|
+
color: var(--text-primary);
|
|
109
|
+
}
|
|
110
|
+
.drawing-section {
|
|
111
|
+
margin-bottom: 16px;
|
|
112
|
+
padding-bottom: 12px;
|
|
113
|
+
border-bottom: 1px solid var(--border-color);
|
|
114
|
+
}
|
|
115
|
+
.drawing-section:last-child {
|
|
116
|
+
border-bottom: none;
|
|
117
|
+
}
|
|
118
|
+
.view-list {
|
|
119
|
+
display: flex;
|
|
120
|
+
flex-direction: column;
|
|
121
|
+
gap: 6px;
|
|
122
|
+
}
|
|
123
|
+
.view-item {
|
|
124
|
+
padding: 8px;
|
|
125
|
+
background: var(--bg-primary);
|
|
126
|
+
border-radius: 3px;
|
|
127
|
+
cursor: pointer;
|
|
128
|
+
transition: background 0.2s;
|
|
129
|
+
font-size: 11px;
|
|
130
|
+
display: flex;
|
|
131
|
+
justify-content: space-between;
|
|
132
|
+
align-items: center;
|
|
133
|
+
}
|
|
134
|
+
.view-item:hover {
|
|
135
|
+
background: var(--bg-tertiary);
|
|
136
|
+
}
|
|
137
|
+
.view-type {
|
|
138
|
+
font-weight: 600;
|
|
139
|
+
color: var(--accent-color);
|
|
140
|
+
}
|
|
141
|
+
.dimension-type-buttons {
|
|
142
|
+
display: grid;
|
|
143
|
+
grid-template-columns: 1fr 1fr;
|
|
144
|
+
gap: 4px;
|
|
145
|
+
margin-bottom: 8px;
|
|
146
|
+
}
|
|
147
|
+
.dimension-type-buttons button {
|
|
148
|
+
padding: 6px;
|
|
149
|
+
font-size: 10px;
|
|
150
|
+
background: var(--button-bg);
|
|
151
|
+
border: 1px solid var(--border-color);
|
|
152
|
+
border-radius: 3px;
|
|
153
|
+
cursor: pointer;
|
|
154
|
+
color: var(--text-primary);
|
|
155
|
+
}
|
|
156
|
+
.dimension-type-buttons button:hover {
|
|
157
|
+
background: var(--button-hover-bg);
|
|
158
|
+
}
|
|
159
|
+
.gdt-frame-selector {
|
|
160
|
+
display: grid;
|
|
161
|
+
grid-template-columns: 1fr 1fr;
|
|
162
|
+
gap: 4px;
|
|
163
|
+
}
|
|
164
|
+
.gdt-frame-selector button {
|
|
165
|
+
padding: 6px;
|
|
166
|
+
font-size: 9px;
|
|
167
|
+
background: var(--button-bg);
|
|
168
|
+
border: 1px solid var(--border-color);
|
|
169
|
+
border-radius: 3px;
|
|
170
|
+
cursor: pointer;
|
|
171
|
+
color: var(--text-primary);
|
|
172
|
+
}
|
|
173
|
+
.title-block-form {
|
|
174
|
+
background: var(--bg-primary);
|
|
175
|
+
padding: 8px;
|
|
176
|
+
border-radius: 3px;
|
|
177
|
+
display: flex;
|
|
178
|
+
flex-direction: column;
|
|
179
|
+
gap: 6px;
|
|
180
|
+
}
|
|
181
|
+
.title-block-form input {
|
|
182
|
+
padding: 4px;
|
|
183
|
+
background: var(--bg-secondary);
|
|
184
|
+
border: 1px solid var(--border-color);
|
|
185
|
+
border-radius: 2px;
|
|
186
|
+
color: var(--text-primary);
|
|
187
|
+
font-size: 11px;
|
|
188
|
+
}
|
|
189
|
+
.bom-table {
|
|
190
|
+
width: 100%;
|
|
191
|
+
border-collapse: collapse;
|
|
192
|
+
font-size: 10px;
|
|
193
|
+
background: var(--bg-primary);
|
|
194
|
+
border-radius: 3px;
|
|
195
|
+
overflow: hidden;
|
|
196
|
+
}
|
|
197
|
+
.bom-table th {
|
|
198
|
+
background: var(--bg-tertiary);
|
|
199
|
+
padding: 4px;
|
|
200
|
+
text-align: left;
|
|
201
|
+
border-bottom: 1px solid var(--border-color);
|
|
202
|
+
}
|
|
203
|
+
.bom-table td {
|
|
204
|
+
padding: 4px;
|
|
205
|
+
border-bottom: 1px solid var(--border-color);
|
|
206
|
+
}
|
|
207
|
+
</style>
|
|
208
|
+
|
|
209
|
+
<div class="drawing-section">
|
|
210
|
+
<h3>Paper Setup</h3>
|
|
211
|
+
<div style="display: flex; gap: 4px; margin-bottom: 8px;">
|
|
212
|
+
<select id="drawingPaperSize" onchange="window.fusionDrawing?.setPaperSize(this.value)" style="flex: 1; padding: 6px; font-size: 11px;">
|
|
213
|
+
<option value="A4">A4</option>
|
|
214
|
+
<option value="A3" selected>A3</option>
|
|
215
|
+
<option value="A2">A2</option>
|
|
216
|
+
<option value="A1">A1</option>
|
|
217
|
+
<option value="Letter">Letter</option>
|
|
218
|
+
<option value="Tabloid">Tabloid</option>
|
|
219
|
+
</select>
|
|
220
|
+
<input type="text" placeholder="Scale" id="drawingScale" value="1:1" style="width: 60px; padding: 6px; font-size: 11px;">
|
|
221
|
+
</div>
|
|
222
|
+
</div>
|
|
223
|
+
|
|
224
|
+
<div class="drawing-section">
|
|
225
|
+
<h3>Views</h3>
|
|
226
|
+
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 4px; margin-bottom: 8px;">
|
|
227
|
+
<button onclick="window.fusionDrawing?.addBaseView('Front')">Base View</button>
|
|
228
|
+
<button onclick="window.fusionDrawing?.addProjectedView()">Projected</button>
|
|
229
|
+
<button onclick="window.fusionDrawing?.addSectionView()">Section</button>
|
|
230
|
+
<button onclick="window.fusionDrawing?.addDetailView()">Detail</button>
|
|
231
|
+
<button onclick="window.fusionDrawing?.addBreakView()">Break</button>
|
|
232
|
+
<button onclick="window.fusionDrawing?.addIsometricView()">Isometric</button>
|
|
233
|
+
</div>
|
|
234
|
+
<div class="view-list" id="drawingViewList"></div>
|
|
235
|
+
</div>
|
|
236
|
+
|
|
237
|
+
<div class="drawing-section">
|
|
238
|
+
<h3>Dimensions</h3>
|
|
239
|
+
<div class="dimension-type-buttons">
|
|
240
|
+
<button onclick="window.fusionDrawing?.addDimension('Linear')">Linear</button>
|
|
241
|
+
<button onclick="window.fusionDrawing?.addDimension('Angular')">Angular</button>
|
|
242
|
+
<button onclick="window.fusionDrawing?.addDimension('Radial')">Radial</button>
|
|
243
|
+
<button onclick="window.fusionDrawing?.addDimension('Diameter')">Diameter</button>
|
|
244
|
+
<button onclick="window.fusionDrawing?.addDimension('Ordinate')">Ordinate</button>
|
|
245
|
+
<button onclick="window.fusionDrawing?.addDimension('Hole Callout')">Hole Callout</button>
|
|
246
|
+
</div>
|
|
247
|
+
<div style="margin-top: 8px;">
|
|
248
|
+
<button onclick="window.fusionDrawing?.addCenterMark()" style="width: 100%; padding: 6px;">Center Mark</button>
|
|
249
|
+
</div>
|
|
250
|
+
</div>
|
|
251
|
+
|
|
252
|
+
<div class="drawing-section">
|
|
253
|
+
<h3>GD&T</h3>
|
|
254
|
+
<div class="gdt-frame-selector">
|
|
255
|
+
<button onclick="window.fusionDrawing?.addGDT('Flatness')">Flatness</button>
|
|
256
|
+
<button onclick="window.fusionDrawing?.addGDT('Parallelism')">Parallelism</button>
|
|
257
|
+
<button onclick="window.fusionDrawing?.addGDT('Perpendicularity')">Perp.</button>
|
|
258
|
+
<button onclick="window.fusionDrawing?.addGDT('Concentricity')">Concentricity</button>
|
|
259
|
+
<button onclick="window.fusionDrawing?.addGDT('Runout')">Runout</button>
|
|
260
|
+
<button onclick="window.fusionDrawing?.addGDT('Position')">Position</button>
|
|
261
|
+
<button onclick="window.fusionDrawing?.addGDT('Profile')">Profile</button>
|
|
262
|
+
<button onclick="window.fusionDrawing?.addGDT('Angularity')">Angularity</button>
|
|
263
|
+
</div>
|
|
264
|
+
</div>
|
|
265
|
+
|
|
266
|
+
<div class="drawing-section">
|
|
267
|
+
<h3>Annotations</h3>
|
|
268
|
+
<div style="display: flex; gap: 4px; margin-bottom: 8px;">
|
|
269
|
+
<button onclick="window.fusionDrawing?.addNote()" style="flex: 1;">Note</button>
|
|
270
|
+
<button onclick="window.fusionDrawing?.addLeader()" style="flex: 1;">Leader</button>
|
|
271
|
+
<button onclick="window.fusionDrawing?.addSurfaceFinish()" style="flex: 1;">Surface</button>
|
|
272
|
+
</div>
|
|
273
|
+
<div style="display: flex; gap: 4px;">
|
|
274
|
+
<button onclick="window.fusionDrawing?.addBalloon()" style="flex: 1;">Balloon</button>
|
|
275
|
+
<button onclick="window.fusionDrawing?.addRevisionTable()" style="flex: 1;">Revision</button>
|
|
276
|
+
</div>
|
|
277
|
+
</div>
|
|
278
|
+
|
|
279
|
+
<div class="drawing-section">
|
|
280
|
+
<h3>Title Block</h3>
|
|
281
|
+
<div class="title-block-form">
|
|
282
|
+
<input type="text" placeholder="Company" id="tbCompany" value="Your Company" onchange="window.fusionDrawing?.updateTitleBlock()">
|
|
283
|
+
<input type="text" placeholder="Designer" id="tbDesigner" value="Designer Name" onchange="window.fusionDrawing?.updateTitleBlock()">
|
|
284
|
+
<input type="text" placeholder="Material" id="tbMaterial" value="Steel" onchange="window.fusionDrawing?.updateTitleBlock()">
|
|
285
|
+
<input type="text" placeholder="Document #" id="tbDocNum" value="000001" onchange="window.fusionDrawing?.updateTitleBlock()">
|
|
286
|
+
</div>
|
|
287
|
+
</div>
|
|
288
|
+
|
|
289
|
+
<div class="drawing-section">
|
|
290
|
+
<h3>Export</h3>
|
|
291
|
+
<div style="display: flex; gap: 4px;">
|
|
292
|
+
<button onclick="window.fusionDrawing?.exportPDF()" style="flex: 1;">PDF</button>
|
|
293
|
+
<button onclick="window.fusionDrawing?.exportDXF()" style="flex: 1;">DXF</button>
|
|
294
|
+
<button onclick="window.fusionDrawing?.printDrawing()" style="flex: 1;">Print</button>
|
|
295
|
+
</div>
|
|
296
|
+
</div>
|
|
297
|
+
`;
|
|
298
|
+
|
|
299
|
+
window.fusionDrawing = this;
|
|
300
|
+
return panel;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Get standard paper dimensions
|
|
305
|
+
*/
|
|
306
|
+
getPaperDimensions() {
|
|
307
|
+
return {
|
|
308
|
+
A4: { width: 210, height: 297 },
|
|
309
|
+
A3: { width: 297, height: 420 },
|
|
310
|
+
A2: { width: 420, height: 594 },
|
|
311
|
+
A1: { width: 594, height: 841 },
|
|
312
|
+
Letter: { width: 216, height: 279 },
|
|
313
|
+
Tabloid: { width: 279, height: 432 }
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Set paper size
|
|
319
|
+
*/
|
|
320
|
+
setPaperSize(size) {
|
|
321
|
+
if (this.paperDimensions[size]) {
|
|
322
|
+
this.paperSize = size;
|
|
323
|
+
this.paperDimensions = this.getPaperDimensions();
|
|
324
|
+
this.drawCanvas();
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Setup drawing canvas
|
|
330
|
+
*/
|
|
331
|
+
setupDrawingCanvas() {
|
|
332
|
+
// Create 2D canvas for drawing
|
|
333
|
+
const canvas = document.createElement('canvas');
|
|
334
|
+
const dims = this.paperDimensions[this.paperSize];
|
|
335
|
+
canvas.width = dims.width * 4; // 4 pixels per mm for detail
|
|
336
|
+
canvas.height = dims.height * 4;
|
|
337
|
+
canvas.style.backgroundColor = '#ffffff';
|
|
338
|
+
|
|
339
|
+
this.drawingCanvas = canvas;
|
|
340
|
+
this.ctx = canvas.getContext('2d');
|
|
341
|
+
this.drawCanvas();
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Draw paper and margins
|
|
346
|
+
*/
|
|
347
|
+
drawCanvas() {
|
|
348
|
+
if (!this.ctx) return;
|
|
349
|
+
|
|
350
|
+
const dims = this.paperDimensions[this.paperSize];
|
|
351
|
+
const pixelScale = 4; // pixels per mm
|
|
352
|
+
|
|
353
|
+
// Clear canvas
|
|
354
|
+
this.ctx.fillStyle = '#ffffff';
|
|
355
|
+
this.ctx.fillRect(0, 0, dims.width * pixelScale, dims.height * pixelScale);
|
|
356
|
+
|
|
357
|
+
// Draw border
|
|
358
|
+
this.ctx.strokeStyle = '#000000';
|
|
359
|
+
this.ctx.lineWidth = 2;
|
|
360
|
+
this.ctx.strokeRect(10 * pixelScale, 10 * pixelScale, (dims.width - 20) * pixelScale, (dims.height - 20) * pixelScale);
|
|
361
|
+
|
|
362
|
+
// Draw title block
|
|
363
|
+
this.drawTitleBlock();
|
|
364
|
+
|
|
365
|
+
// Draw views
|
|
366
|
+
for (const view of this.views.values()) {
|
|
367
|
+
this.drawView(view);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Draw dimensions
|
|
371
|
+
for (const dim of this.dimensions.values()) {
|
|
372
|
+
this.drawDimension(dim);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Draw GD&T frames
|
|
376
|
+
for (const frame of this.gdtFrames.values()) {
|
|
377
|
+
this.drawGDTFrame(frame);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Add base view (front/top/right/isometric)
|
|
383
|
+
*/
|
|
384
|
+
addBaseView(viewType = 'Front') {
|
|
385
|
+
const viewId = `view_${Date.now()}`;
|
|
386
|
+
const view = {
|
|
387
|
+
id: viewId,
|
|
388
|
+
type: viewType,
|
|
389
|
+
viewType: 'Base',
|
|
390
|
+
position: { x: 50, y: 100 },
|
|
391
|
+
scale: 1,
|
|
392
|
+
geometry: null,
|
|
393
|
+
projectionMatrix: new THREE.Matrix4()
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
this.views.set(viewId, view);
|
|
397
|
+
this.baseView = viewId;
|
|
398
|
+
this.updateViewList();
|
|
399
|
+
return viewId;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Add projected view (from base view)
|
|
404
|
+
*/
|
|
405
|
+
addProjectedView() {
|
|
406
|
+
const viewId = `view_${Date.now()}`;
|
|
407
|
+
const view = {
|
|
408
|
+
id: viewId,
|
|
409
|
+
type: 'Projected',
|
|
410
|
+
viewType: 'Projected',
|
|
411
|
+
position: { x: 150, y: 100 },
|
|
412
|
+
baseView: this.baseView,
|
|
413
|
+
scale: 1,
|
|
414
|
+
geometry: null
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
this.views.set(viewId, view);
|
|
418
|
+
this.updateViewList();
|
|
419
|
+
return viewId;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Add section view with hatch pattern
|
|
424
|
+
*/
|
|
425
|
+
addSectionView() {
|
|
426
|
+
const viewId = `view_${Date.now()}`;
|
|
427
|
+
const view = {
|
|
428
|
+
id: viewId,
|
|
429
|
+
type: 'Section A-A',
|
|
430
|
+
viewType: 'Section',
|
|
431
|
+
position: { x: 50, y: 200 },
|
|
432
|
+
sectionPlane: { normal: new THREE.Vector3(0, 1, 0), position: 0 },
|
|
433
|
+
hatchStyle: 'steel',
|
|
434
|
+
geometry: null
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
this.views.set(viewId, view);
|
|
438
|
+
this.updateViewList();
|
|
439
|
+
return viewId;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Add detail view (magnified region)
|
|
444
|
+
*/
|
|
445
|
+
addDetailView() {
|
|
446
|
+
const viewId = `view_${Date.now()}`;
|
|
447
|
+
const view = {
|
|
448
|
+
id: viewId,
|
|
449
|
+
type: 'Detail B',
|
|
450
|
+
viewType: 'Detail',
|
|
451
|
+
position: { x: 250, y: 100 },
|
|
452
|
+
magnification: 2,
|
|
453
|
+
calloutSize: 20,
|
|
454
|
+
geometry: null
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
this.views.set(viewId, view);
|
|
458
|
+
this.updateViewList();
|
|
459
|
+
return viewId;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Add break view (for long thin parts)
|
|
464
|
+
*/
|
|
465
|
+
addBreakView() {
|
|
466
|
+
const viewId = `view_${Date.now()}`;
|
|
467
|
+
const view = {
|
|
468
|
+
id: viewId,
|
|
469
|
+
type: 'Broken View',
|
|
470
|
+
viewType: 'Break',
|
|
471
|
+
position: { x: 150, y: 200 },
|
|
472
|
+
breakType: 'zigzag',
|
|
473
|
+
geometry: null
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
this.views.set(viewId, view);
|
|
477
|
+
this.updateViewList();
|
|
478
|
+
return viewId;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Add isometric view
|
|
483
|
+
*/
|
|
484
|
+
addIsometricView() {
|
|
485
|
+
const viewId = `view_${Date.now()}`;
|
|
486
|
+
const view = {
|
|
487
|
+
id: viewId,
|
|
488
|
+
type: 'Isometric',
|
|
489
|
+
viewType: 'Isometric',
|
|
490
|
+
position: { x: 250, y: 200 },
|
|
491
|
+
scale: 0.8,
|
|
492
|
+
geometry: null
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
this.views.set(viewId, view);
|
|
496
|
+
this.updateViewList();
|
|
497
|
+
return viewId;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Add dimension to drawing
|
|
502
|
+
*/
|
|
503
|
+
addDimension(dimensionType) {
|
|
504
|
+
const dimId = `dim_${Date.now()}`;
|
|
505
|
+
const dimension = {
|
|
506
|
+
id: dimId,
|
|
507
|
+
type: dimensionType, // Linear | Angular | Radial | Diameter | Ordinate | Hole Callout
|
|
508
|
+
position: { x: 100, y: 100 },
|
|
509
|
+
value: 25.0,
|
|
510
|
+
tolerance: { upper: 0.1, lower: 0.1 },
|
|
511
|
+
unit: 'mm',
|
|
512
|
+
isSelected: false
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
this.dimensions.set(dimId, dimension);
|
|
516
|
+
this.updateViewList();
|
|
517
|
+
return dimId;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Add GD&T frame
|
|
522
|
+
*/
|
|
523
|
+
addGDT(gdtType) {
|
|
524
|
+
const frameId = `gdt_${Date.now()}`;
|
|
525
|
+
const frame = {
|
|
526
|
+
id: frameId,
|
|
527
|
+
type: gdtType, // Flatness | Parallelism | Perpendicularity | Concentricity | Runout | Position | Profile | Angularity
|
|
528
|
+
position: { x: 150, y: 150 },
|
|
529
|
+
tolerance: 0.1,
|
|
530
|
+
datumReferences: ['A', null, null], // Up to 3 datums
|
|
531
|
+
modifier: null, // RFS (default) | MMC | LMC
|
|
532
|
+
material: null
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
this.gdtFrames.set(frameId, frame);
|
|
536
|
+
return frameId;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Add center mark
|
|
541
|
+
*/
|
|
542
|
+
addCenterMark() {
|
|
543
|
+
this.centerMarks.push({
|
|
544
|
+
position: { x: 100, y: 100 },
|
|
545
|
+
size: 5
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Add note (text annotation)
|
|
551
|
+
*/
|
|
552
|
+
addNote(text = 'NOTE') {
|
|
553
|
+
this.notes.push({
|
|
554
|
+
position: { x: 50, y: 50 },
|
|
555
|
+
text: text,
|
|
556
|
+
fontSize: 12,
|
|
557
|
+
fontFamily: 'Arial'
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Add leader line
|
|
563
|
+
*/
|
|
564
|
+
addLeader() {
|
|
565
|
+
this.notes.push({
|
|
566
|
+
type: 'leader',
|
|
567
|
+
position: { x: 150, y: 150 },
|
|
568
|
+
text: 'Feature',
|
|
569
|
+
startPoint: { x: 140, y: 140 },
|
|
570
|
+
endPoint: { x: 150, y: 150 }
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Add surface finish symbol
|
|
576
|
+
*/
|
|
577
|
+
addSurfaceFinish() {
|
|
578
|
+
this.notes.push({
|
|
579
|
+
type: 'surface_finish',
|
|
580
|
+
position: { x: 100, y: 100 },
|
|
581
|
+
roughness: 'Ra 1.6',
|
|
582
|
+
method: 'Machine all surfaces'
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Add balloon (BOM reference)
|
|
588
|
+
*/
|
|
589
|
+
addBalloon() {
|
|
590
|
+
this.balloons.push({
|
|
591
|
+
position: { x: 120, y: 120 },
|
|
592
|
+
number: this.balloons.length + 1,
|
|
593
|
+
diameter: 8
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Add revision table
|
|
599
|
+
*/
|
|
600
|
+
addRevisionTable() {
|
|
601
|
+
this.notes.push({
|
|
602
|
+
type: 'revision_table',
|
|
603
|
+
position: { x: 280, y: 20 },
|
|
604
|
+
revisions: [
|
|
605
|
+
{ rev: 'A', date: new Date().toISOString().split('T')[0], description: 'Initial release', approved: 'ECN' }
|
|
606
|
+
]
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* Draw view on canvas
|
|
612
|
+
*/
|
|
613
|
+
drawView(view) {
|
|
614
|
+
const pixelScale = 4;
|
|
615
|
+
const x = view.position.x * pixelScale;
|
|
616
|
+
const y = view.position.y * pixelScale;
|
|
617
|
+
|
|
618
|
+
// Draw view border
|
|
619
|
+
this.ctx.strokeStyle = '#000000';
|
|
620
|
+
this.ctx.lineWidth = 1;
|
|
621
|
+
this.ctx.strokeRect(x, y, 100 * pixelScale, 100 * pixelScale);
|
|
622
|
+
|
|
623
|
+
// Draw view label
|
|
624
|
+
this.ctx.fillStyle = '#000000';
|
|
625
|
+
this.ctx.font = '12px Arial';
|
|
626
|
+
this.ctx.fillText(view.type, x + 5, y + 115 * pixelScale);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* Draw dimension
|
|
631
|
+
*/
|
|
632
|
+
drawDimension(dim) {
|
|
633
|
+
const pixelScale = 4;
|
|
634
|
+
const x = dim.position.x * pixelScale;
|
|
635
|
+
const y = dim.position.y * pixelScale;
|
|
636
|
+
|
|
637
|
+
this.ctx.fillStyle = '#000000';
|
|
638
|
+
this.ctx.font = '11px Arial';
|
|
639
|
+
|
|
640
|
+
// Draw dimension line
|
|
641
|
+
this.ctx.strokeStyle = '#000000';
|
|
642
|
+
this.ctx.lineWidth = 0.5;
|
|
643
|
+
this.ctx.beginPath();
|
|
644
|
+
this.ctx.moveTo(x, y);
|
|
645
|
+
this.ctx.lineTo(x + 50 * pixelScale, y);
|
|
646
|
+
this.ctx.stroke();
|
|
647
|
+
|
|
648
|
+
// Draw dimension text
|
|
649
|
+
const dimText = `${dim.value.toFixed(1)}`;
|
|
650
|
+
this.ctx.fillText(dimText, x + 15 * pixelScale, y - 5);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* Draw GD&T frame
|
|
655
|
+
*/
|
|
656
|
+
drawGDTFrame(frame) {
|
|
657
|
+
const pixelScale = 4;
|
|
658
|
+
const x = frame.position.x * pixelScale;
|
|
659
|
+
const y = frame.position.y * pixelScale;
|
|
660
|
+
const frameHeight = 14;
|
|
661
|
+
const frameWidth = 40;
|
|
662
|
+
|
|
663
|
+
// Draw frame boxes
|
|
664
|
+
this.ctx.strokeStyle = '#000000';
|
|
665
|
+
this.ctx.lineWidth = 1;
|
|
666
|
+
|
|
667
|
+
// First box: GD&T symbol
|
|
668
|
+
this.ctx.strokeRect(x, y, frameWidth, frameHeight);
|
|
669
|
+
this.ctx.fillStyle = '#000000';
|
|
670
|
+
this.ctx.font = '10px Arial';
|
|
671
|
+
this.ctx.fillText(frame.type.substring(0, 1), x + 5, y + 10);
|
|
672
|
+
|
|
673
|
+
// Second box: tolerance value
|
|
674
|
+
this.ctx.strokeRect(x + frameWidth, y, frameWidth, frameHeight);
|
|
675
|
+
this.ctx.fillText(frame.tolerance.toFixed(2), x + frameWidth + 5, y + 10);
|
|
676
|
+
|
|
677
|
+
// Third box: datum
|
|
678
|
+
if (frame.datumReferences[0]) {
|
|
679
|
+
this.ctx.strokeRect(x + frameWidth * 2, y, frameWidth, frameHeight);
|
|
680
|
+
this.ctx.fillText(frame.datumReferences[0], x + frameWidth * 2 + 5, y + 10);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Draw title block
|
|
686
|
+
*/
|
|
687
|
+
drawTitleBlock() {
|
|
688
|
+
const dims = this.paperDimensions[this.paperSize];
|
|
689
|
+
const pixelScale = 4;
|
|
690
|
+
const marginX = (dims.width - 80) * pixelScale;
|
|
691
|
+
const marginY = (dims.height - 40) * pixelScale;
|
|
692
|
+
|
|
693
|
+
// Draw title block border
|
|
694
|
+
this.ctx.strokeStyle = '#000000';
|
|
695
|
+
this.ctx.lineWidth = 1;
|
|
696
|
+
this.ctx.strokeRect(marginX, marginY, 80 * pixelScale, 30 * pixelScale);
|
|
697
|
+
|
|
698
|
+
// Draw title block content
|
|
699
|
+
this.ctx.fillStyle = '#000000';
|
|
700
|
+
this.ctx.font = 'bold 12px Arial';
|
|
701
|
+
this.ctx.fillText('TITLE BLOCK', marginX + 10, marginY + 15);
|
|
702
|
+
|
|
703
|
+
this.ctx.font = '10px Arial';
|
|
704
|
+
this.ctx.fillText(`Company: ${this.titleBlock.company}`, marginX + 10, marginY + 30);
|
|
705
|
+
this.ctx.fillText(`Designer: ${this.titleBlock.designer}`, marginX + 10, marginY + 45);
|
|
706
|
+
this.ctx.fillText(`Scale: ${this.titleBlock.scale}`, marginX + 10, marginY + 60);
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* Update title block from form
|
|
711
|
+
*/
|
|
712
|
+
updateTitleBlock() {
|
|
713
|
+
this.titleBlock.company = document.getElementById('tbCompany')?.value || 'Your Company';
|
|
714
|
+
this.titleBlock.designer = document.getElementById('tbDesigner')?.value || 'Designer Name';
|
|
715
|
+
this.titleBlock.material = document.getElementById('tbMaterial')?.value || 'Steel';
|
|
716
|
+
this.titleBlock.documentNumber = document.getElementById('tbDocNum')?.value || '000001';
|
|
717
|
+
this.drawCanvas();
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
* Update view list display
|
|
722
|
+
*/
|
|
723
|
+
updateViewList() {
|
|
724
|
+
const listDiv = document.getElementById('drawingViewList');
|
|
725
|
+
if (!listDiv) return;
|
|
726
|
+
|
|
727
|
+
listDiv.innerHTML = '';
|
|
728
|
+
for (const [viewId, view] of this.views) {
|
|
729
|
+
const itemDiv = document.createElement('div');
|
|
730
|
+
itemDiv.className = 'view-item';
|
|
731
|
+
itemDiv.innerHTML = `
|
|
732
|
+
<span class="view-type">${view.type}</span>
|
|
733
|
+
<button onclick="window.fusionDrawing?.deleteView('${viewId}')" style="padding: 2px 6px; font-size: 10px;">Delete</button>
|
|
734
|
+
`;
|
|
735
|
+
listDiv.appendChild(itemDiv);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* Delete view
|
|
741
|
+
*/
|
|
742
|
+
deleteView(viewId) {
|
|
743
|
+
this.views.delete(viewId);
|
|
744
|
+
this.updateViewList();
|
|
745
|
+
this.drawCanvas();
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* Export drawing to PDF
|
|
750
|
+
*/
|
|
751
|
+
exportPDF() {
|
|
752
|
+
if (!this.drawingCanvas) return;
|
|
753
|
+
|
|
754
|
+
// Create PDF (simplified — using canvas-to-pdf approach)
|
|
755
|
+
const link = document.createElement('a');
|
|
756
|
+
link.href = this.drawingCanvas.toDataURL('image/png');
|
|
757
|
+
link.download = `drawing_${this.titleBlock.documentNumber}.png`;
|
|
758
|
+
link.click();
|
|
759
|
+
|
|
760
|
+
console.log('PDF export created (using PNG fallback)');
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
/**
|
|
764
|
+
* Export drawing to DXF
|
|
765
|
+
*/
|
|
766
|
+
exportDXF() {
|
|
767
|
+
let dxf = '';
|
|
768
|
+
dxf += '0\nSECTION\n2\nHEADER\n';
|
|
769
|
+
dxf += '9\n$ACADVER\n1\nAC1021\n';
|
|
770
|
+
dxf += '0\nENDSEC\n';
|
|
771
|
+
|
|
772
|
+
// Entities section
|
|
773
|
+
dxf += '0\nSECTION\n2\nENTITIES\n';
|
|
774
|
+
|
|
775
|
+
// Add views as MTEXT
|
|
776
|
+
for (const [viewId, view] of this.views) {
|
|
777
|
+
dxf += `0\nMTEXT\n8\n0\n10\n${view.position.x}\n20\n${view.position.y}\n1\n${view.type}\n`;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// Add dimensions
|
|
781
|
+
for (const [dimId, dim] of this.dimensions) {
|
|
782
|
+
dxf += `0\nDIMENSION\n8\n0\n10\n${dim.position.x}\n20\n${dim.position.y}\n1\n${dim.value}\n`;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
dxf += '0\nENDSEC\n';
|
|
786
|
+
dxf += '0\nEOF\n';
|
|
787
|
+
|
|
788
|
+
// Download DXF
|
|
789
|
+
const blob = new Blob([dxf], { type: 'text/plain' });
|
|
790
|
+
const url = URL.createObjectURL(blob);
|
|
791
|
+
const a = document.createElement('a');
|
|
792
|
+
a.href = url;
|
|
793
|
+
a.download = `drawing_${this.titleBlock.documentNumber}.dxf`;
|
|
794
|
+
a.click();
|
|
795
|
+
URL.revokeObjectURL(url);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/**
|
|
799
|
+
* Print drawing
|
|
800
|
+
*/
|
|
801
|
+
printDrawing() {
|
|
802
|
+
if (!this.drawingCanvas) return;
|
|
803
|
+
|
|
804
|
+
const printWindow = window.open();
|
|
805
|
+
printWindow.document.write(`<img src="${this.drawingCanvas.toDataURL()}" style="width:100%;">`);
|
|
806
|
+
printWindow.document.close();
|
|
807
|
+
printWindow.print();
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
/**
|
|
811
|
+
* Setup event listeners
|
|
812
|
+
*/
|
|
813
|
+
setupEventListeners() {
|
|
814
|
+
// Listen for dimension creation
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* Execute command from agent API
|
|
819
|
+
*/
|
|
820
|
+
execute(command, params) {
|
|
821
|
+
switch (command) {
|
|
822
|
+
case 'addBaseView':
|
|
823
|
+
return this.addBaseView(params.type);
|
|
824
|
+
case 'addProjectedView':
|
|
825
|
+
return this.addProjectedView();
|
|
826
|
+
case 'addDimension':
|
|
827
|
+
return this.addDimension(params.dimensionType);
|
|
828
|
+
case 'addGDT':
|
|
829
|
+
return this.addGDT(params.gdtType);
|
|
830
|
+
case 'addCenterMark':
|
|
831
|
+
return this.addCenterMark();
|
|
832
|
+
case 'setPaperSize':
|
|
833
|
+
return this.setPaperSize(params.size);
|
|
834
|
+
case 'exportPDF':
|
|
835
|
+
return this.exportPDF();
|
|
836
|
+
case 'exportDXF':
|
|
837
|
+
return this.exportDXF();
|
|
838
|
+
default:
|
|
839
|
+
console.warn(`Unknown drawing command: ${command}`);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
export default FusionDrawingModule;
|