@atlisp/mcp 1.8.15 → 1.8.17
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/handlers/3d-handlers.js +128 -0
- package/dist/handlers/batch-handlers.js +260 -0
- package/dist/handlers/block-handlers.js +214 -0
- package/dist/handlers/cad-handlers.js +180 -0
- package/dist/handlers/constraint-handlers.js +130 -0
- package/dist/handlers/dim-hatch-handlers.js +340 -0
- package/dist/handlers/draw-handlers.js +175 -0
- package/dist/handlers/edit-handlers.js +179 -0
- package/dist/handlers/entity-handlers.js +196 -0
- package/dist/handlers/external-handlers.js +218 -0
- package/dist/handlers/file-handlers.js +172 -0
- package/dist/handlers/function-handlers.js +158 -0
- package/dist/handlers/layer-handlers.js +181 -0
- package/dist/handlers/package-handlers.js +89 -0
- package/dist/handlers/parametric-handlers.js +272 -0
- package/dist/handlers/pdf-annotation-handlers.js +117 -0
- package/dist/handlers/prompt-handlers.js +9 -0
- package/dist/handlers/purge-handlers.js +137 -0
- package/dist/handlers/query-print-handlers.js +662 -0
- package/dist/handlers/resource-cache.js +63 -0
- package/dist/handlers/resource-defs.js +79 -0
- package/dist/handlers/resource-handlers.js +131 -0
- package/dist/handlers/resource-readers.js +1045 -0
- package/dist/handlers/sheetset-handlers.js +430 -0
- package/dist/handlers/spatial-handlers.js +174 -0
- package/dist/handlers/style-handlers.js +162 -0
- package/dist/handlers/text-handlers.js +198 -0
- package/dist/handlers/ucs-layout-handlers.js +271 -0
- package/dist/handlers/viewport-handlers.js +150 -0
- package/dist/handlers/xdata-handlers.js +148 -0
- package/dist/handlers/xref-handlers.js +334 -0
- package/dist/lisp-security.js +7 -2
- package/package.json +2 -2
|
@@ -0,0 +1,662 @@
|
|
|
1
|
+
import { cad } from '../cad.js';
|
|
2
|
+
import { escapeLispString } from '../handler-utils.js';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import os from 'os';
|
|
6
|
+
|
|
7
|
+
function toSafePoint(pt) {
|
|
8
|
+
const parts = (Array.isArray(pt) ? pt : String(pt).split(/[,\s]+/)).map(Number);
|
|
9
|
+
return parts.filter(n => !isNaN(n)).join(' ');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function plotToPdf(outputPath, layout = 'Model', style = {}) {
|
|
13
|
+
if (!cad.connected) { await cad.connect(); }
|
|
14
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
15
|
+
|
|
16
|
+
const paperSize = style.paperSize || 'A4';
|
|
17
|
+
const code = `(progn
|
|
18
|
+
(vl-load-com)
|
|
19
|
+
(setq doc (vla-get-activedocument (vlax-get-acad-object)))
|
|
20
|
+
(vlax-for layout (vla-get-layouts doc)
|
|
21
|
+
(if (or (eq (vla-get-name layout) "${escapeLispString(layout)}") (eq "${escapeLispString(layout)}" "Model"))
|
|
22
|
+
(progn
|
|
23
|
+
(vla-put-active layout)
|
|
24
|
+
(vla-plottofile doc "${escapeLispString(outputPath)}" "${escapeLispString(paperSize)}")
|
|
25
|
+
(setq result "EXPORTED")
|
|
26
|
+
)
|
|
27
|
+
)
|
|
28
|
+
)
|
|
29
|
+
(if result result "FAILED")
|
|
30
|
+
)`;
|
|
31
|
+
try {
|
|
32
|
+
const result = await cad.sendCommandWithResult(code);
|
|
33
|
+
if (result === 'EXPORTED' || result === '"EXPORTED"') {
|
|
34
|
+
return { content: [{ type: 'text', text: `已打印到 PDF: ${outputPath}` }] };
|
|
35
|
+
}
|
|
36
|
+
return { content: [{ type: 'text', text: `打印失败: ${result}` }], isError: true };
|
|
37
|
+
} catch (e) {
|
|
38
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function plotToPrinter(printerName, layout = 'Model') {
|
|
43
|
+
if (!cad.connected) { await cad.connect(); }
|
|
44
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
45
|
+
|
|
46
|
+
const code = `(progn
|
|
47
|
+
(vl-load-com)
|
|
48
|
+
(setq doc (vla-get-activedocument (vlax-get-acad-object)))
|
|
49
|
+
(vlax-for layout (vla-get-layouts doc)
|
|
50
|
+
(if (or (eq (vla-get-name layout) "${escapeLispString(layout)}") (eq "${escapeLispString(layout)}" "Model"))
|
|
51
|
+
(progn
|
|
52
|
+
(vla-put-active layout)
|
|
53
|
+
(vla-plottofile doc "${escapeLispString(printerName)}")
|
|
54
|
+
(setq result "PRINTED")
|
|
55
|
+
)
|
|
56
|
+
)
|
|
57
|
+
)
|
|
58
|
+
(if result result "FAILED")
|
|
59
|
+
)`;
|
|
60
|
+
try {
|
|
61
|
+
const result = await cad.sendCommandWithResult(code);
|
|
62
|
+
return { content: [{ type: 'text', text: result === 'PRINTED' ? '已发送到打印机' : '打印失败' }] };
|
|
63
|
+
} catch (e) {
|
|
64
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function createGroup(name, handles) {
|
|
69
|
+
if (!cad.connected) { await cad.connect(); }
|
|
70
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
71
|
+
|
|
72
|
+
if (!Array.isArray(handles) || handles.length === 0) {
|
|
73
|
+
return { content: [{ type: 'text', text: '句柄列表为空' }], isError: true };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const handlesCode = handles.map(h => `(ssadd (handent "${escapeLispString(h)}") ss)`).join('\n');
|
|
77
|
+
const code = `(progn
|
|
78
|
+
(vl-load-com)
|
|
79
|
+
(setq ss (ssadd))
|
|
80
|
+
${handlesCode}
|
|
81
|
+
(command "._GROUP" "C" "${escapeLispString(name)}" "" ss "")
|
|
82
|
+
"CREATED"
|
|
83
|
+
)`;
|
|
84
|
+
try {
|
|
85
|
+
const result = await cad.sendCommandWithResult(code);
|
|
86
|
+
if (result === 'CREATED' || result === '"CREATED"') {
|
|
87
|
+
return { content: [{ type: 'text', text: `已创建组: ${name}` }] };
|
|
88
|
+
}
|
|
89
|
+
return { content: [{ type: 'text', text: `创建失败: ${result}` }], isError: true };
|
|
90
|
+
} catch (e) {
|
|
91
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export async function deleteGroup(name) {
|
|
96
|
+
if (!cad.connected) { await cad.connect(); }
|
|
97
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
98
|
+
|
|
99
|
+
const code = `(progn
|
|
100
|
+
(vl-load-com)
|
|
101
|
+
(setq @dict (dictsearch (namedobjdict) "ACAD_GROUP"))
|
|
102
|
+
(if (and @dict (dictsearch (cdr (assoc -1 @dict)) "${escapeLispString(name)}"))
|
|
103
|
+
(progn
|
|
104
|
+
(command "._GROUP" "D" "${escapeLispString(name)}")
|
|
105
|
+
"DELETED"
|
|
106
|
+
)
|
|
107
|
+
"NOTFOUND"
|
|
108
|
+
)
|
|
109
|
+
)`;
|
|
110
|
+
try {
|
|
111
|
+
const result = await cad.sendCommandWithResult(code);
|
|
112
|
+
if (result === 'DELETED' || result === '"DELETED"') {
|
|
113
|
+
return { content: [{ type: 'text', text: `已删除组: ${name}` }] };
|
|
114
|
+
}
|
|
115
|
+
return { content: [{ type: 'text', text: result === 'NOTFOUND' ? `组不存在: ${name}` : '删除失败' }], isError: true };
|
|
116
|
+
} catch (e) {
|
|
117
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export async function listGroups() {
|
|
122
|
+
if (!cad.connected) { await cad.connect(); }
|
|
123
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
124
|
+
|
|
125
|
+
const code = `(progn
|
|
126
|
+
(vl-load-com)
|
|
127
|
+
(setq @groups nil)
|
|
128
|
+
(setq @dict (dictsearch (namedobjdict) "ACAD_GROUP"))
|
|
129
|
+
(if @dict
|
|
130
|
+
(setq @group-dict (cdr (assoc -1 @dict)))
|
|
131
|
+
(setq @group-dict nil))
|
|
132
|
+
(if @group-dict
|
|
133
|
+
(progn
|
|
134
|
+
(setq @entry (dictsearch @group-dict "*"))
|
|
135
|
+
(while @entry
|
|
136
|
+
(setq @groups (cons (cdr (assoc 3 @entry)) @groups))
|
|
137
|
+
(setq @entry (dictsearch @group-dict @entry))
|
|
138
|
+
)
|
|
139
|
+
(vl-prin1-to-string (reverse @groups))
|
|
140
|
+
)
|
|
141
|
+
"nil"
|
|
142
|
+
)
|
|
143
|
+
)`;
|
|
144
|
+
try {
|
|
145
|
+
const result = await cad.sendCommandWithResult(code);
|
|
146
|
+
return { content: [{ type: 'text', text: result || '无组' }] };
|
|
147
|
+
} catch (e) {
|
|
148
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export async function getGroupEntities(groupName) {
|
|
153
|
+
if (!cad.connected) { await cad.connect(); }
|
|
154
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
155
|
+
|
|
156
|
+
const code = `(progn
|
|
157
|
+
(vl-load-com)
|
|
158
|
+
(setq @dict (dictsearch (namedobjdict) "ACAD_GROUP"))
|
|
159
|
+
(if (and @dict (dictsearch (cdr (assoc -1 @dict)) "${escapeLispString(groupName)}"))
|
|
160
|
+
(progn
|
|
161
|
+
(command "._SELECT" "G" "${escapeLispString(groupName)}" "")
|
|
162
|
+
(if (and (getvar 'ssmode) (ssget-first))
|
|
163
|
+
(progn
|
|
164
|
+
(setq ss (ssget "+" (list (cons 410 (getvar 'ctab)))))
|
|
165
|
+
(if ss
|
|
166
|
+
(progn
|
|
167
|
+
(setq cnt (sslength ss) handles nil i 0)
|
|
168
|
+
(while (< i cnt)
|
|
169
|
+
(setq handles (cons (cdr (assoc 5 (entget (ssname ss i)))) handles))
|
|
170
|
+
(setq i (1+ i)))
|
|
171
|
+
(reverse handles)
|
|
172
|
+
)
|
|
173
|
+
nil
|
|
174
|
+
)
|
|
175
|
+
(sssetfirst nil)
|
|
176
|
+
)
|
|
177
|
+
nil
|
|
178
|
+
)
|
|
179
|
+
)
|
|
180
|
+
nil
|
|
181
|
+
)
|
|
182
|
+
)`;
|
|
183
|
+
try {
|
|
184
|
+
const result = await cad.sendCommandWithResult(code);
|
|
185
|
+
return { content: [{ type: 'text', text: result || '无实体' }] };
|
|
186
|
+
} catch (e) {
|
|
187
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export async function measureDistance(p1, p2) {
|
|
192
|
+
if (!cad.connected) { await cad.connect(); }
|
|
193
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
194
|
+
|
|
195
|
+
const code = `(progn
|
|
196
|
+
(vl-load-com)
|
|
197
|
+
(setq pt1 (list ${toSafePoint(p1)}) pt2 (list ${toSafePoint(p2)}))
|
|
198
|
+
(setq dist (distance pt1 pt2))
|
|
199
|
+
(setq ang (angle pt1 pt2))
|
|
200
|
+
(list
|
|
201
|
+
(strcat "Distance: " (rtos dist 2 4))
|
|
202
|
+
(strcat "Angle: " (rtos (* 180 (/ ang pi)) 2 2) "°")
|
|
203
|
+
(strcat "DX: " (rtos (- (car pt2) (car pt1)) 2 4))
|
|
204
|
+
(strcat "DY: " (rtos (- (cadr pt2) (cadr pt1)) 2 4))
|
|
205
|
+
)
|
|
206
|
+
)`;
|
|
207
|
+
try {
|
|
208
|
+
const result = await cad.sendCommandWithResult(code);
|
|
209
|
+
return { content: [{ type: 'text', text: result || '测量失败' }] };
|
|
210
|
+
} catch (e) {
|
|
211
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export async function measureArea(points) {
|
|
216
|
+
if (!cad.connected) { await cad.connect(); }
|
|
217
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
218
|
+
|
|
219
|
+
const pts = Array.isArray(points) ? points : points.split(/[\s,]+/).filter(Boolean);
|
|
220
|
+
if (pts.length < 3) {
|
|
221
|
+
return { content: [{ type: 'text', text: '至少需要 3 个点' }], isError: true };
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const coords = pts.map((p, i) => {
|
|
225
|
+
const parts = String(p).split(',').map(Number);
|
|
226
|
+
return parts.length >= 2 && !isNaN(parts[0]) && !isNaN(parts[1])
|
|
227
|
+
? `(list ${parts[0]} ${parts[1]})`
|
|
228
|
+
: '(list 0 0)';
|
|
229
|
+
}).join(' ');
|
|
230
|
+
|
|
231
|
+
const code = `(progn
|
|
232
|
+
(vl-load-com)
|
|
233
|
+
(setq pts (list ${coords}))
|
|
234
|
+
(if (>= (length pts) 3)
|
|
235
|
+
(progn
|
|
236
|
+
(command "._PLINE")
|
|
237
|
+
(foreach p pts (command p))
|
|
238
|
+
(command "")
|
|
239
|
+
(command "._AREA" "O" "L")
|
|
240
|
+
(list
|
|
241
|
+
(strcat "Area: " (rtos (getvar 'area) 2 4) " sq units")
|
|
242
|
+
(strcat "Perimeter: " (rtos (getvar 'perimeter) 2 4))
|
|
243
|
+
)
|
|
244
|
+
)
|
|
245
|
+
"NEED_3_POINTS"
|
|
246
|
+
)
|
|
247
|
+
)`;
|
|
248
|
+
try {
|
|
249
|
+
const result = await cad.sendCommandWithResult(code);
|
|
250
|
+
return { content: [{ type: 'text', text: result || '测量失败' }] };
|
|
251
|
+
} catch (e) {
|
|
252
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export async function publishLayouts(args) {
|
|
257
|
+
if (!cad.connected) { await cad.connect(); }
|
|
258
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
259
|
+
|
|
260
|
+
const layouts = Array.isArray(args.layouts) ? args.layouts : [args.layouts || 'Model'];
|
|
261
|
+
const outputDir = args.outputDir || '.';
|
|
262
|
+
const namingRule = args.namingRule || '{layout}';
|
|
263
|
+
const format = args.format || 'PDF';
|
|
264
|
+
const merge = args.merge !== false;
|
|
265
|
+
|
|
266
|
+
let results = [];
|
|
267
|
+
for (const layout of layouts) {
|
|
268
|
+
try {
|
|
269
|
+
const safeName = String(layout).replace(/[^a-zA-Z0-9_\-\u4e00-\u9fff]/g, '_');
|
|
270
|
+
const outputPath = namingRule.replace('{layout}', safeName).replace('{format}', format.toLowerCase());
|
|
271
|
+
const fullPath = outputDir.endsWith('/') || outputDir.endsWith('\\')
|
|
272
|
+
? `${outputDir}${outputPath}.${format.toLowerCase()}`
|
|
273
|
+
: `${outputDir}/${outputPath}.${format.toLowerCase()}`;
|
|
274
|
+
|
|
275
|
+
const result = await cad.sendCommandWithResult(`(progn
|
|
276
|
+
(vl-load-com)
|
|
277
|
+
(setq doc (vla-get-activedocument (vlax-get-acad-object)))
|
|
278
|
+
(setq found nil)
|
|
279
|
+
(vlax-for l (vla-get-layouts doc)
|
|
280
|
+
(if (= (vla-get-name l) "${escapeLispString(layout)}")
|
|
281
|
+
(progn
|
|
282
|
+
(vla-put-active l)
|
|
283
|
+
(vla-plottofile doc "${escapeLispString(fullPath)}" "A4")
|
|
284
|
+
(setq found "ok")
|
|
285
|
+
)
|
|
286
|
+
)
|
|
287
|
+
)
|
|
288
|
+
(if found (princ found) (princ "not found"))
|
|
289
|
+
)`);
|
|
290
|
+
results.push({ layout, outputPath: fullPath, success: result === 'ok' });
|
|
291
|
+
} catch (e) {
|
|
292
|
+
results.push({ layout, outputPath: '', success: false, error: e.message });
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const successCount = results.filter(r => r.success).length;
|
|
297
|
+
const msg = `布局批量发布完成: 成功 ${successCount}/${results.length}`;
|
|
298
|
+
return {
|
|
299
|
+
content: [{
|
|
300
|
+
type: 'text',
|
|
301
|
+
text: JSON.stringify({ summary: msg, results })
|
|
302
|
+
}],
|
|
303
|
+
isError: successCount < results.length
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export async function batchPlotWizard(args) {
|
|
308
|
+
if (!cad.connected) { await cad.connect(); }
|
|
309
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
310
|
+
|
|
311
|
+
const layouts = Array.isArray(args.layouts) ? args.layouts : [args.layouts || 'Model'];
|
|
312
|
+
const outputDir = args.outputDir || '.';
|
|
313
|
+
const format = (args.format || 'PDF').toUpperCase();
|
|
314
|
+
const namingRule = args.namingRule || '{layout}';
|
|
315
|
+
const pageSetup = args.pageSetup || '';
|
|
316
|
+
|
|
317
|
+
const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
|
318
|
+
const results = [];
|
|
319
|
+
|
|
320
|
+
for (const layout of layouts) {
|
|
321
|
+
try {
|
|
322
|
+
const safeName = String(layout).replace(/[^a-zA-Z0-9_\-\u4e00-\u9fff]/g, '_');
|
|
323
|
+
const outputName = namingRule
|
|
324
|
+
.replace('{layout}', safeName)
|
|
325
|
+
.replace('{date}', dateStr)
|
|
326
|
+
.replace('{format}', format.toLowerCase());
|
|
327
|
+
const fullPath = outputDir.endsWith('/') || outputDir.endsWith('\\')
|
|
328
|
+
? `${outputDir}${outputName}.${format.toLowerCase()}`
|
|
329
|
+
: `${outputDir}/${outputName}.${format.toLowerCase()}`;
|
|
330
|
+
|
|
331
|
+
const preview = args.preview === true;
|
|
332
|
+
if (preview) {
|
|
333
|
+
results.push({ layout, outputPath: fullPath, status: 'PREVIEW' });
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const code = `(progn
|
|
338
|
+
(vl-load-com)
|
|
339
|
+
(setq doc (vla-get-activedocument (vlax-get-acad-object)))
|
|
340
|
+
(setq found nil)
|
|
341
|
+
(vlax-for l (vla-get-layouts doc)
|
|
342
|
+
(if (= (vla-get-name l) "${escapeLispString(layout)}")
|
|
343
|
+
(progn
|
|
344
|
+
(vla-put-active l)
|
|
345
|
+
${pageSetup ? `(vla-put-activelayout doc "${escapeLispString(pageSetup)}")` : ''}
|
|
346
|
+
(vla-plottofile doc "${escapeLispString(fullPath)}" "A4")
|
|
347
|
+
(setq found "ok")
|
|
348
|
+
)
|
|
349
|
+
)
|
|
350
|
+
)
|
|
351
|
+
(if found found "not found")
|
|
352
|
+
)`;
|
|
353
|
+
const result = await cad.sendCommandWithResult(code);
|
|
354
|
+
results.push({ layout, outputPath: fullPath, status: result === 'ok' ? 'EXPORTED' : 'FAILED', raw: result });
|
|
355
|
+
} catch (e) {
|
|
356
|
+
results.push({ layout, outputPath: '', status: 'ERROR', error: e.message });
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const successCount = results.filter(r => r.status === 'EXPORTED').length;
|
|
361
|
+
return {
|
|
362
|
+
content: [{
|
|
363
|
+
type: 'text',
|
|
364
|
+
text: JSON.stringify({
|
|
365
|
+
summary: `批量打印完成: 成功 ${successCount}/${results.length}`,
|
|
366
|
+
total: results.length,
|
|
367
|
+
success: successCount,
|
|
368
|
+
results
|
|
369
|
+
})
|
|
370
|
+
}],
|
|
371
|
+
isError: successCount < results.length
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
export async function plotDeviceManagement(args) {
|
|
376
|
+
if (!cad.connected) { await cad.connect(); }
|
|
377
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
378
|
+
|
|
379
|
+
const action = (args.action || 'list').toLowerCase();
|
|
380
|
+
|
|
381
|
+
try {
|
|
382
|
+
if (action === 'list') {
|
|
383
|
+
const code = `(progn
|
|
384
|
+
(vl-load-com)
|
|
385
|
+
(setq cfg (vla-get-plotconfigurations (vla-get-activedocument (vlax-get-acad-object))))
|
|
386
|
+
(setq devices nil i 0)
|
|
387
|
+
(vlax-for pc cfg
|
|
388
|
+
(setq devices (cons
|
|
389
|
+
(list
|
|
390
|
+
"name" (vla-get-name pc)
|
|
391
|
+
"description" (vla-get-description pc)
|
|
392
|
+
"paperSizes" (vlax-get pc 'CanonicalMediaNames)
|
|
393
|
+
"isValid" (vla-get-valid pc)
|
|
394
|
+
)
|
|
395
|
+
devices
|
|
396
|
+
))
|
|
397
|
+
)
|
|
398
|
+
(reverse devices)
|
|
399
|
+
)`;
|
|
400
|
+
const result = await cad.sendCommandWithResult(code);
|
|
401
|
+
return { content: [{ type: 'text', text: result || '无打印设备' }] };
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (action === 'get') {
|
|
405
|
+
const name = args.name || '';
|
|
406
|
+
if (!name) return { content: [{ type: 'text', text: '需要 name 参数' }], isError: true };
|
|
407
|
+
const code = `(progn
|
|
408
|
+
(vl-load-com)
|
|
409
|
+
(setq cfg (vla-get-plotconfigurations (vla-get-activedocument (vlax-get-acad-object))))
|
|
410
|
+
(setq found nil)
|
|
411
|
+
(vlax-for pc cfg
|
|
412
|
+
(if (= (vla-get-name pc) "${escapeLispString(name)}")
|
|
413
|
+
(setq found (list
|
|
414
|
+
"name" (vla-get-name pc)
|
|
415
|
+
"description" (vla-get-description pc)
|
|
416
|
+
"paperSizes" (vlax-get pc 'CanonicalMediaNames)
|
|
417
|
+
"isValid" (vla-get-valid pc)
|
|
418
|
+
"locDeviceName" (vlax-get pc 'LocDeviceName)
|
|
419
|
+
))
|
|
420
|
+
)
|
|
421
|
+
)
|
|
422
|
+
(if found found (strcat "NOTFOUND:" "${escapeLispString(name)}"))
|
|
423
|
+
)`;
|
|
424
|
+
const result = await cad.sendCommandWithResult(code);
|
|
425
|
+
return { content: [{ type: 'text', text: result }] };
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
if (action === 'set') {
|
|
429
|
+
const name = args.name || '';
|
|
430
|
+
if (!name) return { content: [{ type: 'text', text: '需要 name 参数' }], isError: true };
|
|
431
|
+
const code = `(progn
|
|
432
|
+
(vl-load-com)
|
|
433
|
+
(setq doc (vla-get-activedocument (vlax-get-acad-object)))
|
|
434
|
+
(vla-put-activeplotconfig doc "${escapeLispString(name)}")
|
|
435
|
+
(if (= (vla-get-activeplotconfig doc) "${escapeLispString(name)}") "SET" "FAILED")
|
|
436
|
+
)`;
|
|
437
|
+
const result = await cad.sendCommandWithResult(code);
|
|
438
|
+
return { content: [{ type: 'text', text: result === 'SET' ? `打印设备已设为: ${name}` : `设置失败: ${result || name}` }] };
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
if (action === 'test') {
|
|
442
|
+
const name = args.name;
|
|
443
|
+
const code = `(progn
|
|
444
|
+
(vl-load-com)
|
|
445
|
+
(setq doc (vla-get-activedocument (vlax-get-acad-object)))
|
|
446
|
+
${name ? `(vla-put-activeplotconfig doc "${escapeLispString(name)}")` : ''}
|
|
447
|
+
(setq cfg (vla-get-activeplotconfig doc))
|
|
448
|
+
(list
|
|
449
|
+
"name" cfg
|
|
450
|
+
"canPlot" (if (vl-catch-all-error-p (vl-catch-all-apply 'vla-plottofile (list doc (strcat (vl-filename-mktemp) ".pdf") "A4"))) "FAIL" "OK")
|
|
451
|
+
)
|
|
452
|
+
)`;
|
|
453
|
+
const result = await cad.sendCommandWithResult(code);
|
|
454
|
+
return { content: [{ type: 'text', text: result || '测试失败' }] };
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
return { content: [{ type: 'text', text: `未知 action: ${action}` }], isError: true };
|
|
458
|
+
} catch (e) {
|
|
459
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
export async function plotLog(args) {
|
|
464
|
+
const homedir = os.homedir ? os.homedir() : (process.env.HOME || process.env.USERPROFILE || '');
|
|
465
|
+
const logPath = path.join(homedir, '.atlisp', 'plot-log.json');
|
|
466
|
+
|
|
467
|
+
let logs = [];
|
|
468
|
+
try {
|
|
469
|
+
if (fs.existsSync(logPath)) {
|
|
470
|
+
const raw = fs.readFileSync(logPath, 'utf-8');
|
|
471
|
+
logs = JSON.parse(raw);
|
|
472
|
+
if (!Array.isArray(logs)) logs = [];
|
|
473
|
+
}
|
|
474
|
+
} catch {
|
|
475
|
+
logs = [];
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const from = args.fromDate ? new Date(args.fromDate).getTime() : 0;
|
|
479
|
+
const to = args.toDate ? new Date(args.toDate).getTime() : Date.now() + 86400000;
|
|
480
|
+
const status = args.status ? args.status.toLowerCase() : '';
|
|
481
|
+
|
|
482
|
+
const filtered = logs.filter(entry => {
|
|
483
|
+
const t = new Date(entry.timestamp || entry.date || 0).getTime();
|
|
484
|
+
if (t < from || t > to) return false;
|
|
485
|
+
if (status && (entry.status || '').toLowerCase() !== status) return false;
|
|
486
|
+
return true;
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
return {
|
|
490
|
+
content: [{
|
|
491
|
+
type: 'text',
|
|
492
|
+
text: JSON.stringify({
|
|
493
|
+
total: filtered.length,
|
|
494
|
+
fromDate: args.fromDate || null,
|
|
495
|
+
toDate: args.toDate || null,
|
|
496
|
+
statusFilter: args.status || null,
|
|
497
|
+
entries: filtered
|
|
498
|
+
})
|
|
499
|
+
}]
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
export async function plotFromFileList(args) {
|
|
504
|
+
if (!cad.connected) { await cad.connect(); }
|
|
505
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
506
|
+
|
|
507
|
+
let fileList = [];
|
|
508
|
+
if (Array.isArray(args.fileList)) {
|
|
509
|
+
fileList = args.fileList;
|
|
510
|
+
} else if (args.textFile) {
|
|
511
|
+
try {
|
|
512
|
+
const content = fs.readFileSync(args.textFile, 'utf-8');
|
|
513
|
+
const lines = content.split(/\r?\n/).filter(Boolean);
|
|
514
|
+
fileList = lines.map(line => {
|
|
515
|
+
const parts = line.split('|').map(s => s.trim());
|
|
516
|
+
return { dwgPath: parts[0], layout: parts[1] || 'Model', outputPath: parts[2] || '' };
|
|
517
|
+
});
|
|
518
|
+
} catch (e) {
|
|
519
|
+
return { content: [{ type: 'text', text: `读取文件失败: ${e.message}` }], isError: true };
|
|
520
|
+
}
|
|
521
|
+
} else {
|
|
522
|
+
return { content: [{ type: 'text', text: '需要 fileList 或 textFile' }], isError: true };
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
if (fileList.length === 0) {
|
|
526
|
+
return { content: [{ type: 'text', text: '文件列表为空' }], isError: true };
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
const results = [];
|
|
530
|
+
|
|
531
|
+
for (const item of fileList) {
|
|
532
|
+
try {
|
|
533
|
+
const dwgPath = item.dwgPath;
|
|
534
|
+
const layout = item.layout || 'Model';
|
|
535
|
+
let outputPath = item.outputPath;
|
|
536
|
+
|
|
537
|
+
if (!dwgPath) {
|
|
538
|
+
results.push({ dwgPath: '', layout, outputPath: '', status: 'ERROR', error: '缺少 dwgPath' });
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
if (!outputPath) {
|
|
543
|
+
const ext = '.pdf';
|
|
544
|
+
outputPath = dwgPath.replace(/\.dwg$/i, '') + `_${layout}${ext}`;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
let openResult;
|
|
548
|
+
if (dwgPath) {
|
|
549
|
+
openResult = await cad.sendCommandWithResult(`(progn
|
|
550
|
+
(vl-load-com)
|
|
551
|
+
(setq doc (vla-open (vla-get-documents (vlax-get-acad-object)) "${escapeLispString(dwgPath)}"))
|
|
552
|
+
(if doc "OPENED" "FAILED")
|
|
553
|
+
)`);
|
|
554
|
+
if (openResult !== 'OPENED') {
|
|
555
|
+
results.push({ dwgPath, layout, outputPath, status: 'ERROR', error: `打开文件失败: ${openResult || ''}` });
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
const code = `(progn
|
|
561
|
+
(vl-load-com)
|
|
562
|
+
(setq doc (vla-get-activedocument (vlax-get-acad-object)))
|
|
563
|
+
(setq found nil)
|
|
564
|
+
(vlax-for l (vla-get-layouts doc)
|
|
565
|
+
(if (= (vla-get-name l) "${escapeLispString(layout)}")
|
|
566
|
+
(progn
|
|
567
|
+
(vla-put-active l)
|
|
568
|
+
(vla-plottofile doc "${escapeLispString(outputPath)}" "A4")
|
|
569
|
+
(setq found "ok")
|
|
570
|
+
)
|
|
571
|
+
)
|
|
572
|
+
)
|
|
573
|
+
(if found found "not found")
|
|
574
|
+
)`;
|
|
575
|
+
const result = await cad.sendCommandWithResult(code);
|
|
576
|
+
results.push({ dwgPath, layout, outputPath, status: result === 'ok' ? 'EXPORTED' : 'FAILED', raw: result });
|
|
577
|
+
} catch (e) {
|
|
578
|
+
results.push({ dwgPath: item.dwgPath || '', layout: item.layout || 'Model', outputPath: item.outputPath || '', status: 'ERROR', error: e.message });
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
const successCount = results.filter(r => r.status === 'EXPORTED').length;
|
|
583
|
+
return {
|
|
584
|
+
content: [{
|
|
585
|
+
type: 'text',
|
|
586
|
+
text: JSON.stringify({
|
|
587
|
+
summary: `文件列表批量打印完成: 成功 ${successCount}/${results.length}`,
|
|
588
|
+
total: results.length,
|
|
589
|
+
success: successCount,
|
|
590
|
+
results
|
|
591
|
+
})
|
|
592
|
+
}],
|
|
593
|
+
isError: successCount < results.length
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
export async function getEntityInfo(handle) {
|
|
598
|
+
if (!cad.connected) { await cad.connect(); }
|
|
599
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
600
|
+
|
|
601
|
+
const code = `(progn
|
|
602
|
+
(vl-load-com)
|
|
603
|
+
(if (setq ent (handent "${escapeLispString(handle)}"))
|
|
604
|
+
(progn
|
|
605
|
+
(setq ed (entget ent) typ (cdr (assoc 0 ed)))
|
|
606
|
+
(list
|
|
607
|
+
"type" typ
|
|
608
|
+
"handle" (cdr (assoc 5 ed))
|
|
609
|
+
"layer" (cdr (assoc 8 ed))
|
|
610
|
+
"color" (if (assoc 62 ed) (cdr (assoc 62 ed)) 256)
|
|
611
|
+
"linetype" (if (assoc 6 ed) (cdr (assoc 6 ed)) "ByLayer")
|
|
612
|
+
"layerFrozen" (if (assoc 70 ed) (/= (logand (cdr (assoc 70 ed)) 1) 0) nil)
|
|
613
|
+
"layerLocked" (if (assoc 70 ed) (/= (logand (cdr (assoc 70 ed)) 4) 0) nil)
|
|
614
|
+
)
|
|
615
|
+
)
|
|
616
|
+
nil
|
|
617
|
+
)
|
|
618
|
+
)`;
|
|
619
|
+
try {
|
|
620
|
+
const result = await cad.sendCommandWithResult(code);
|
|
621
|
+
if (!result || result === 'nil') {
|
|
622
|
+
return { content: [{ type: 'text', text: `未找到实体: ${handle}` }], isError: true };
|
|
623
|
+
}
|
|
624
|
+
return { content: [{ type: 'text', text: result }] };
|
|
625
|
+
} catch (e) {
|
|
626
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
export async function createPageSetup(name, printer = 'DWG To PDF.pc3', paperSize = 'A4', orientation = 'Landscape', scale = '1:1') {
|
|
631
|
+
if (!cad.connected) { await cad.connect(); }
|
|
632
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
633
|
+
try {
|
|
634
|
+
await cad.sendCommand(`(command "_.-PAGESETUP" "${escapeLispString(name)}" "" "" "${escapeLispString(printer)}" "${escapeLispString(paperSize)}" "${orientation}" "N" "${scale}" "1=1" "" "N" "" "" "")\n`);
|
|
635
|
+
return { content: [{ type: 'text', text: `已创建页面设置: ${name}` }] };
|
|
636
|
+
} catch (e) { return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true }; }
|
|
637
|
+
}
|
|
638
|
+
export async function listPageSetups() {
|
|
639
|
+
if (!cad.connected) { await cad.connect(); }
|
|
640
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
641
|
+
try {
|
|
642
|
+
const result = await cad.sendCommandWithResult('(progn (setq setups nil) (vlax-for ps (vla-get-plotconfigurations (vla-get-activedocument (vlax-get-acad-object))) (setq setups (cons (vla-get-name ps) setups))) (reverse setups))');
|
|
643
|
+
return { content: [{ type: 'text', text: result || '[]' }] };
|
|
644
|
+
} catch (e) { return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true }; }
|
|
645
|
+
}
|
|
646
|
+
export async function setPageSetup(layout, pageSetupName) {
|
|
647
|
+
if (!cad.connected) { await cad.connect(); }
|
|
648
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
649
|
+
try {
|
|
650
|
+
await cad.sendCommand(`(command "_.-PAGESETUP" "${escapeLispString(pageSetupName)}" "" "${escapeLispString(layout)}")\n`);
|
|
651
|
+
return { content: [{ type: 'text', text: `已为布局 ${layout} 设置页面设置: ${pageSetupName}` }] };
|
|
652
|
+
} catch (e) { return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true }; }
|
|
653
|
+
}
|
|
654
|
+
export async function importPageSetup(dwgPath, pageSetupName = null) {
|
|
655
|
+
if (!cad.connected) { await cad.connect(); }
|
|
656
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
657
|
+
try {
|
|
658
|
+
const namePart = pageSetupName ? ` "${escapeLispString(pageSetupName)}"` : ' "*"';
|
|
659
|
+
await cad.sendCommand(`(command "_.-PSETUPIN" "${escapeLispString(dwgPath)}" ${namePart})\n`);
|
|
660
|
+
return { content: [{ type: 'text', text: `已导入页面设置: ${dwgPath}` }] };
|
|
661
|
+
} catch (e) { return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true }; }
|
|
662
|
+
}
|