@atlisp/mcp 1.8.16 → 1.8.18
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/atlisp-mcp.js +1 -10
- 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,180 @@
|
|
|
1
|
+
import { cad } from '../cad.js';
|
|
2
|
+
import { log } from '../logger.js';
|
|
3
|
+
import { escapeLispString } from '../handler-utils.js';
|
|
4
|
+
|
|
5
|
+
export async function connectCad(platform = null) {
|
|
6
|
+
log(`connect_cad called${platform ? ` (target: ${platform})` : ''}, cad.connected before: ${cad.connected}`);
|
|
7
|
+
try {
|
|
8
|
+
log('calling cad.connect()...');
|
|
9
|
+
const connected = await cad.connect(platform);
|
|
10
|
+
log('cad.connect() returned: ' + connected + ', cad.connected: ' + cad.connected);
|
|
11
|
+
if (connected) {
|
|
12
|
+
const messages = [`已连接到 ${cad.getPlatform()} ${cad.getVersion()}`];
|
|
13
|
+
initAtlisp().catch(e => log(`connect_cad: initAtlisp failed: ${e.message}`));
|
|
14
|
+
return { content: [{ type: 'text', text: messages.join(';') }] };
|
|
15
|
+
}
|
|
16
|
+
return { content: [{ type: 'text', text: '未能连接或启动 CAD,请确保 CAD 已安装' }], isError: true };
|
|
17
|
+
} catch (e) {
|
|
18
|
+
log('connect_cad error: ' + e.message);
|
|
19
|
+
return { content: [{ type: 'text', text: `连接 CAD 失败: ${e.message}` }], isError: true };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function evalLisp(code, withResult = false, encoding = null) {
|
|
24
|
+
if (!cad.connected) { await cad.connect(); }
|
|
25
|
+
if (!cad.connected) {
|
|
26
|
+
return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
27
|
+
}
|
|
28
|
+
const trimmed = (code || '').trim();
|
|
29
|
+
if (!trimmed) return { content: [{ type: 'text', text: '命令为空,未发送' }] };
|
|
30
|
+
try {
|
|
31
|
+
if (withResult) {
|
|
32
|
+
const result = await cad.sendCommandWithResult(trimmed, encoding);
|
|
33
|
+
if (result !== null) {
|
|
34
|
+
return { content: [{ type: 'text', text: result }] };
|
|
35
|
+
}
|
|
36
|
+
return { content: [{ type: 'text', text: '执行失败或无返回值' }], isError: true };
|
|
37
|
+
} else {
|
|
38
|
+
await cad.sendCommand(trimmed + '\n');
|
|
39
|
+
return { content: [{ type: 'text', text: `已发送命令` }] };
|
|
40
|
+
}
|
|
41
|
+
} catch (e) {
|
|
42
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function getCadInfo() {
|
|
47
|
+
if (!cad.connected) { await cad.connect(); }
|
|
48
|
+
if (!cad.connected) return { content: [{ type: 'text', text: 'CAD 未连接' }] };
|
|
49
|
+
const info = await cad.getInfo();
|
|
50
|
+
return { content: [{ type: 'text', text: info }] };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function atCommand(command) {
|
|
54
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '请先连接 CAD' }], isError: true };
|
|
55
|
+
const trimmed = (command || '').trim();
|
|
56
|
+
if (!trimmed) return { content: [{ type: 'text', text: '命令为空,未发送' }] };
|
|
57
|
+
await cad.sendCommand(trimmed + '\n');
|
|
58
|
+
return { content: [{ type: 'text', text: '已发送命令' }] };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function newDocument() {
|
|
62
|
+
if (!cad.connected) { await cad.connect(); }
|
|
63
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
64
|
+
const result = await cad.newDoc();
|
|
65
|
+
if (result) {
|
|
66
|
+
return { content: [{ type: 'text', text: '已在 CAD 中新建空白文档' }] };
|
|
67
|
+
}
|
|
68
|
+
return { content: [{ type: 'text', text: '新建文档失败' }], isError: true };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export async function bringToFront() {
|
|
72
|
+
if (!cad.connected) { await cad.connect(); }
|
|
73
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
74
|
+
const result = await cad.bringToFront();
|
|
75
|
+
if (result) {
|
|
76
|
+
return { content: [{ type: 'text', text: '已将 CAD 窗口切换到前台' }] };
|
|
77
|
+
}
|
|
78
|
+
return { content: [{ type: 'text', text: '切换前台失败' }], isError: true };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export async function installAtlisp() {
|
|
82
|
+
if (!cad.connected) { await cad.connect(); }
|
|
83
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
84
|
+
const installCode = '(progn(vl-load-com)(setq s strcat h "http" o(vlax-create-object (s"win"h".win"h"request.5.1"))v vlax-invoke e eval r read)(v o\'open "get" (s h"://atlisp.""cn/@"):vlax-true)(v o\'send)(v o\'WaitforResponse 1000)(e(r(vlax-get-property o\'ResponseText))))';
|
|
85
|
+
await cad.sendCommand(installCode + '\n');
|
|
86
|
+
return { content: [{ type: 'text', text: '已发送 @lisp 安装代码到 CAD' }] };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export async function listFunctionsInCad() {
|
|
90
|
+
if (!cad.connected) { await cad.connect(); }
|
|
91
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
92
|
+
try {
|
|
93
|
+
const result = await cad.sendCommandWithResult('(atoms-family 0)', null);
|
|
94
|
+
if (result) return { content: [{ type: 'text', text: result }] };
|
|
95
|
+
return { content: [{ type: 'text', text: 'CAD 函数列表为空' }] };
|
|
96
|
+
} catch (e) {
|
|
97
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export async function getSystemStatus() {
|
|
102
|
+
const status = {
|
|
103
|
+
mcp: { version: process.env.npm_package_version || 'unknown' },
|
|
104
|
+
worker: { alive: false },
|
|
105
|
+
cad: { connected: false, platform: null, version: null, busy: false, hasDoc: false },
|
|
106
|
+
lisp: { available: false, testResult: null, error: null },
|
|
107
|
+
packages: null,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
status.worker.alive = await cad.ping();
|
|
112
|
+
} catch { status.worker.alive = false; }
|
|
113
|
+
|
|
114
|
+
status.cad.connected = cad.connected;
|
|
115
|
+
if (cad.connected) {
|
|
116
|
+
status.cad.platform = cad.getPlatform();
|
|
117
|
+
status.cad.version = cad.getVersion();
|
|
118
|
+
try { status.cad.busy = await cad.isBusy(); } catch (e) { log(`cad-handlers: isBusy error: ${e.message}`); }
|
|
119
|
+
try {
|
|
120
|
+
const doc = await cad.hasDoc();
|
|
121
|
+
status.cad.hasDoc = doc.hasDoc;
|
|
122
|
+
} catch (e) { log(`cad-handlers: hasDoc error: ${e.message}`); }
|
|
123
|
+
try {
|
|
124
|
+
const r = await cad.sendCommandWithResult('(+ 1 2)');
|
|
125
|
+
if (r !== null && r !== undefined) {
|
|
126
|
+
status.lisp.available = true;
|
|
127
|
+
status.lisp.testResult = String(r).trim();
|
|
128
|
+
}
|
|
129
|
+
} catch (e) {
|
|
130
|
+
status.lisp.error = e.message;
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
const pkgResult = await cad.sendCommandWithResult('(@::package-list-in-local)');
|
|
134
|
+
if (pkgResult && pkgResult !== 'nil') {
|
|
135
|
+
status.packages = pkgResult;
|
|
136
|
+
}
|
|
137
|
+
} catch (e) { log(`cad-handlers: getSystemStatus package-list error: ${e.message}`); }
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return { content: [{ type: 'text', text: JSON.stringify(status, null, 2) }] };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export async function initAtlisp() {
|
|
144
|
+
if (!cad.connected) { await cad.connect(); }
|
|
145
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
146
|
+
const code = `(if (null @::load-module)
|
|
147
|
+
(progn
|
|
148
|
+
(vl-load-com)
|
|
149
|
+
(setq s strcat h"http"o(vlax-create-object (s"win"h".win"h"request.5.1"))
|
|
150
|
+
v vlax-invoke e eval r read)(v o'open "get" (s h"://""atlisp.""cn/cloud"):vlax-true)
|
|
151
|
+
(v o'send)
|
|
152
|
+
(v o'WaitforResponse 1000)
|
|
153
|
+
(e(r(vlax-get o'ResponseText)))))`;
|
|
154
|
+
try {
|
|
155
|
+
await cad.sendCommand(code + '\n');
|
|
156
|
+
return { content: [{ type: 'text', text: '已发送 @lisp 函数库加载代码到 CAD' }] };
|
|
157
|
+
} catch (e) {
|
|
158
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
export async function getSystemVariable(name) {
|
|
162
|
+
if (!cad.connected) { await cad.connect(); }
|
|
163
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
164
|
+
try {
|
|
165
|
+
const result = await cad.sendCommandWithResult(`(vl-princ-to-string (getvar "${escapeLispString(name)}"))`);
|
|
166
|
+
return { content: [{ type: 'text', text: result || 'nil' }] };
|
|
167
|
+
} catch (e) {
|
|
168
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
export async function setSystemVariable(name, value) {
|
|
172
|
+
if (!cad.connected) { await cad.connect(); }
|
|
173
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
174
|
+
try {
|
|
175
|
+
await cad.sendCommand(`(setvar "${escapeLispString(name)}" ${value})\n`);
|
|
176
|
+
return { content: [{ type: 'text', text: `已设置 ${name} = ${value}` }] };
|
|
177
|
+
} catch (e) {
|
|
178
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
179
|
+
}
|
|
180
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { cad } from '../cad.js';
|
|
2
|
+
import { mcpSuccess, mcpError, escapeLispString } from '../handler-utils.js';
|
|
3
|
+
|
|
4
|
+
function esc(s) {
|
|
5
|
+
return escapeLispString(String(s || ''));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function ptStr(pt) {
|
|
9
|
+
if (!pt) return '';
|
|
10
|
+
const parts = String(pt).split(',').map(Number);
|
|
11
|
+
return `(list ${parts[0] || 0} ${parts[1] || 0} ${parts[2] || 0})`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function addGeomConstraint(args) {
|
|
15
|
+
try {
|
|
16
|
+
if (!cad.connected) await cad.connect();
|
|
17
|
+
if (!cad.connected) return mcpError('未连接 CAD');
|
|
18
|
+
const ctype = esc(args.type);
|
|
19
|
+
const h1 = esc(args.handle1);
|
|
20
|
+
const h2 = esc(args.handle2 || '');
|
|
21
|
+
const p1 = ptStr(args.point1);
|
|
22
|
+
const p2 = ptStr(args.point2);
|
|
23
|
+
|
|
24
|
+
const code = `(progn
|
|
25
|
+
(vl-load-com)
|
|
26
|
+
(setq doc (vla-get-activedocument (vlax-get-acad-object)))
|
|
27
|
+
(setq assm (vla-get-associativeconstraints doc))
|
|
28
|
+
(setq e1 (handent "${h1}"))
|
|
29
|
+
${h2 ? `(setq e2 (handent "${h2}"))` : '(setq e2 nil)'}
|
|
30
|
+
(if e1
|
|
31
|
+
(progn
|
|
32
|
+
(setq vobj1 (vlax-ename->vla-object e1))
|
|
33
|
+
${h2 ? '(setq vobj2 (vlax-ename->vla-object e2))' : '(setq vobj2 nil)'}
|
|
34
|
+
(vlax-invoke assm 'AddConstraint "${ctype}" vobj1 ${h2 ? 'vobj2' : 'nil'} ${p1 || 'nil'} ${p2 || 'nil'})
|
|
35
|
+
(princ "ok")
|
|
36
|
+
)
|
|
37
|
+
(princ "nf")
|
|
38
|
+
)
|
|
39
|
+
)`;
|
|
40
|
+
const result = await cad.sendCommandWithResult(code);
|
|
41
|
+
if (result === 'ok') return mcpSuccess(`几何约束已添加: ${ctype}`);
|
|
42
|
+
return mcpError(`添加约束失败: ${result}`);
|
|
43
|
+
} catch (e) {
|
|
44
|
+
return mcpError(`错误: ${e.message}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function addDimConstraint(args) {
|
|
49
|
+
try {
|
|
50
|
+
if (!cad.connected) await cad.connect();
|
|
51
|
+
if (!cad.connected) return mcpError('未连接 CAD');
|
|
52
|
+
const ctype = esc(args.type);
|
|
53
|
+
const h = esc(args.handle);
|
|
54
|
+
const val = parseFloat(args.value) || 0;
|
|
55
|
+
const p1 = ptStr(args.point1);
|
|
56
|
+
const p2 = ptStr(args.point2);
|
|
57
|
+
|
|
58
|
+
const code = `(progn
|
|
59
|
+
(vl-load-com)
|
|
60
|
+
(setq doc (vla-get-activedocument (vlax-get-acad-object)))
|
|
61
|
+
(setq assm (vla-get-associativeconstraints doc))
|
|
62
|
+
(setq e (handent "${h}"))
|
|
63
|
+
(if e
|
|
64
|
+
(progn
|
|
65
|
+
(setq vobj (vlax-ename->vla-object e))
|
|
66
|
+
(setq dim (vlax-invoke assm 'AddDimConstraint "${ctype}" vobj ${p1 || 'nil'} ${p2 || 'nil'} nil nil ${val} nil))
|
|
67
|
+
(princ "ok")
|
|
68
|
+
)
|
|
69
|
+
(princ "nf")
|
|
70
|
+
)
|
|
71
|
+
)`;
|
|
72
|
+
const result = await cad.sendCommandWithResult(code);
|
|
73
|
+
if (result === 'ok') return mcpSuccess(`标注约束已添加: ${ctype} = ${val}`);
|
|
74
|
+
return mcpError(`添加标注约束失败: ${result}`);
|
|
75
|
+
} catch (e) {
|
|
76
|
+
return mcpError(`错误: ${e.message}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export async function delConstraint(args) {
|
|
81
|
+
try {
|
|
82
|
+
if (!cad.connected) await cad.connect();
|
|
83
|
+
if (!cad.connected) return mcpError('未连接 CAD');
|
|
84
|
+
const h = esc(args.handle);
|
|
85
|
+
const code = `(progn
|
|
86
|
+
(vl-load-com)
|
|
87
|
+
(setq doc (vla-get-activedocument (vlax-get-acad-object)))
|
|
88
|
+
(setq assm (vla-get-associativeconstraints doc))
|
|
89
|
+
(setq e (handent "${h}"))
|
|
90
|
+
(if e
|
|
91
|
+
(progn
|
|
92
|
+
(setq vobj (vlax-ename->vla-object e))
|
|
93
|
+
(vlax-invoke assm 'DeleteConstraintsOnObject vobj)
|
|
94
|
+
(princ "ok")
|
|
95
|
+
)
|
|
96
|
+
(princ "nf")
|
|
97
|
+
)
|
|
98
|
+
)`;
|
|
99
|
+
const result = await cad.sendCommandWithResult(code);
|
|
100
|
+
if (result === 'ok') return mcpSuccess('约束已删除');
|
|
101
|
+
return mcpError(`删除约束失败: ${result}`);
|
|
102
|
+
} catch (e) {
|
|
103
|
+
return mcpError(`错误: ${e.message}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export async function listConstraints() {
|
|
108
|
+
try {
|
|
109
|
+
if (!cad.connected) await cad.connect();
|
|
110
|
+
if (!cad.connected) return mcpError('未连接 CAD');
|
|
111
|
+
const code = `(progn
|
|
112
|
+
(vl-load-com)
|
|
113
|
+
(setq doc (vla-get-activedocument (vlax-get-acad-object)))
|
|
114
|
+
(setq assm (vla-get-associativeconstraints doc))
|
|
115
|
+
(setq result nil)
|
|
116
|
+
(vlax-for c (vla-get-constraints assm)
|
|
117
|
+
(setq result (cons (list
|
|
118
|
+
(cons "type" (vla-get-constrainttype c))
|
|
119
|
+
(cons "expression" (vla-get-expression c))
|
|
120
|
+
(cons "value" (vla-get-value c))
|
|
121
|
+
) result))
|
|
122
|
+
)
|
|
123
|
+
(if result (vl-princ-to-string result) "[]")
|
|
124
|
+
)`;
|
|
125
|
+
const result = await cad.sendCommandWithResult(code);
|
|
126
|
+
return mcpSuccess(result || '[]');
|
|
127
|
+
} catch (e) {
|
|
128
|
+
return mcpError(`错误: ${e.message}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
import { cad } from '../cad.js';
|
|
2
|
+
import { escapeLispString } from '../handler-utils.js';
|
|
3
|
+
|
|
4
|
+
function toSafePoint(pt) {
|
|
5
|
+
const parts = (Array.isArray(pt) ? pt : String(pt).split(/[,\s]+/)).map(Number);
|
|
6
|
+
return parts.filter(n => !isNaN(n)).join(' ');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function createDimension(type, points, style = {}) {
|
|
10
|
+
if (!cad.connected) { await cad.connect(); }
|
|
11
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
12
|
+
|
|
13
|
+
let dimCode = '';
|
|
14
|
+
const validTypes = ['ALIGNED', 'LINEAR', 'ORDINATE', 'RADIAL', 'DIAMETER', 'ANGULAR'];
|
|
15
|
+
const dimType = (type || 'ALIGNED').toUpperCase();
|
|
16
|
+
|
|
17
|
+
if (!validTypes.includes(dimType)) {
|
|
18
|
+
return { content: [{ type: 'text', text: `不支持的标注类型: ${type}` }], isError: true };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const defPt = toSafePoint(points.defPt || '0,0');
|
|
22
|
+
const pt1 = toSafePoint(points.pt1 || points.pt || '0,0');
|
|
23
|
+
const pt2 = toSafePoint(points.pt2 || '100,0');
|
|
24
|
+
const leaderLen = parseFloat(style.leaderLength) || 10;
|
|
25
|
+
|
|
26
|
+
switch (dimType) {
|
|
27
|
+
case 'ALIGNED':
|
|
28
|
+
dimCode = `(command "._DIMALIGNED" (list ${pt1}) (list ${pt2}) (list ${defPt}))`;
|
|
29
|
+
break;
|
|
30
|
+
case 'LINEAR':
|
|
31
|
+
dimCode = `(command "._DIMLINEAR" (list ${pt1}) (list ${pt2}) (list ${defPt}))`;
|
|
32
|
+
break;
|
|
33
|
+
case 'ORDINATE':
|
|
34
|
+
dimCode = `(command "._DIMORDINATE" (list ${pt1}) (list ${defPt}))`;
|
|
35
|
+
break;
|
|
36
|
+
case 'RADIAL':
|
|
37
|
+
dimCode = `(command "._DIMRADIUS" (list ${defPt}) "${leaderLen}")`;
|
|
38
|
+
break;
|
|
39
|
+
case 'DIAMETER':
|
|
40
|
+
dimCode = `(command "._DIMDIAMETER" (list ${defPt}) "${leaderLen}")`;
|
|
41
|
+
break;
|
|
42
|
+
case 'ANGULAR':
|
|
43
|
+
dimCode = `(command "._DIMANGULAR" (list ${pt1}) (list ${pt2}) (list ${defPt}))`;
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
await cad.sendCommand(dimCode + '\n');
|
|
49
|
+
return { content: [{ type: 'text', text: `已创建 ${dimType} 标注` }] };
|
|
50
|
+
} catch (e) {
|
|
51
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function getDimensionValue(handle) {
|
|
56
|
+
if (!cad.connected) { await cad.connect(); }
|
|
57
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
58
|
+
|
|
59
|
+
const code = `(progn
|
|
60
|
+
(vl-load-com)
|
|
61
|
+
(if (setq ent (handent "${escapeLispString(handle)}"))
|
|
62
|
+
(progn
|
|
63
|
+
(setq ed (entget ent) typ (cdr (assoc 0 ed)))
|
|
64
|
+
(if (wcmatch typ "DIMENSION")
|
|
65
|
+
(list
|
|
66
|
+
"type" typ
|
|
67
|
+
"handle" (cdr (assoc 5 ed))
|
|
68
|
+
"layer" (cdr (assoc 8 ed))
|
|
69
|
+
"style" (if (assoc 2 ed) (cdr (assoc 2 ed)) "Standard")
|
|
70
|
+
"measurement" (if (assoc 42 ed) (rtos (cdr (assoc 42 ed)) 2 2) "0")
|
|
71
|
+
)
|
|
72
|
+
(list "error" "Not a dimension entity")
|
|
73
|
+
)
|
|
74
|
+
)
|
|
75
|
+
(list "error" "Entity not found")
|
|
76
|
+
)
|
|
77
|
+
)`;
|
|
78
|
+
try {
|
|
79
|
+
const result = await cad.sendCommandWithResult(code);
|
|
80
|
+
return { content: [{ type: 'text', text: result || '获取失败' }] };
|
|
81
|
+
} catch (e) {
|
|
82
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export async function createHatch(patternName, boundary, scale = 1, angle = 0) {
|
|
87
|
+
if (!cad.connected) { await cad.connect(); }
|
|
88
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
89
|
+
|
|
90
|
+
const code = `(progn
|
|
91
|
+
(vl-load-com)
|
|
92
|
+
(command "._BHATCH" "p" "${escapeLispString(patternName)}" "s" "s" "sc" ${scale} "an" ${angle} "")
|
|
93
|
+
"CREATED"
|
|
94
|
+
)`;
|
|
95
|
+
try {
|
|
96
|
+
const result = await cad.sendCommandWithResult(code);
|
|
97
|
+
if (result && result !== 'nil') {
|
|
98
|
+
return { content: [{ type: 'text', text: `已创建图案填充: ${patternName}` }] };
|
|
99
|
+
}
|
|
100
|
+
return { content: [{ type: 'text', text: '创建填充失败' }], isError: true };
|
|
101
|
+
} catch (e) {
|
|
102
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export async function setHatchProperties(handle, props) {
|
|
107
|
+
if (!cad.connected) { await cad.connect(); }
|
|
108
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
109
|
+
|
|
110
|
+
let propCode = '';
|
|
111
|
+
if (props.pattern) propCode += `(command "._HATCHEDIT" "${escapeLispString(handle)}" "p" "${escapeLispString(props.pattern)}")`;
|
|
112
|
+
if (props.scale) propCode += `(command "._HATCHEDIT" "${escapeLispString(handle)}" "s" ${parseFloat(props.scale) || 1})`;
|
|
113
|
+
if (props.angle) propCode += `(command "._HATCHEDIT" "${escapeLispString(handle)}" "an" ${parseFloat(props.angle) || 0})`;
|
|
114
|
+
if (props.color) propCode += `(command "._HATCHEDIT" "${escapeLispString(handle)}" "c" ${parseInt(props.color) || 256})`;
|
|
115
|
+
|
|
116
|
+
const code = `(progn
|
|
117
|
+
(vl-load-com)
|
|
118
|
+
${propCode}
|
|
119
|
+
"UPDATED"
|
|
120
|
+
)`;
|
|
121
|
+
try {
|
|
122
|
+
const result = await cad.sendCommandWithResult(code);
|
|
123
|
+
return { content: [{ type: 'text', text: `已更新填充属性` }] };
|
|
124
|
+
} catch (e) {
|
|
125
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export async function getBlockAttributes(blockHandle) {
|
|
130
|
+
if (!cad.connected) { await cad.connect(); }
|
|
131
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
132
|
+
|
|
133
|
+
const code = `(progn
|
|
134
|
+
(vl-load-com)
|
|
135
|
+
(if (setq ent (handent "${escapeLispString(blockHandle)}"))
|
|
136
|
+
(if (= (cdr (assoc 0 (entget ent))) "INSERT")
|
|
137
|
+
(progn
|
|
138
|
+
(setq atts nil)
|
|
139
|
+
(setq att (entnext ent))
|
|
140
|
+
(while (and att (= (cdr (assoc 0 (entget att))) "ATTRIB"))
|
|
141
|
+
(setq atts (cons
|
|
142
|
+
(list (cdr (assoc 2 (entget att))) (cdr (assoc 1 (entget att))))
|
|
143
|
+
atts))
|
|
144
|
+
(setq att (entnext att)))
|
|
145
|
+
(reverse atts))
|
|
146
|
+
(list "error" "Not a block reference"))
|
|
147
|
+
(list "error" "Entity not found"))
|
|
148
|
+
)`;
|
|
149
|
+
try {
|
|
150
|
+
const result = await cad.sendCommandWithResult(code);
|
|
151
|
+
return { content: [{ type: 'text', text: result || '无属性' }] };
|
|
152
|
+
} catch (e) {
|
|
153
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export async function setBlockAttribute(blockHandle, tag, value) {
|
|
158
|
+
if (!cad.connected) { await cad.connect(); }
|
|
159
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
160
|
+
|
|
161
|
+
const code = `(progn
|
|
162
|
+
(vl-load-com)
|
|
163
|
+
(if (setq ent (handent "${escapeLispString(blockHandle)}"))
|
|
164
|
+
(progn
|
|
165
|
+
(setq att (entnext ent))
|
|
166
|
+
(while att
|
|
167
|
+
(if (= (cdr (assoc 0 (entget att))) "ATTRIB")
|
|
168
|
+
(if (= (strcase (cdr (assoc 2 (entget att)))) (strcase "${escapeLispString(tag)}"))
|
|
169
|
+
(progn
|
|
170
|
+
(entmod (subst (cons 1 "${escapeLispString(value)}") (assoc 1 (entget att)) (entget att)))
|
|
171
|
+
(setq att nil)
|
|
172
|
+
)
|
|
173
|
+
)
|
|
174
|
+
)
|
|
175
|
+
(setq att (entnext att))
|
|
176
|
+
)
|
|
177
|
+
"UPDATED"
|
|
178
|
+
)
|
|
179
|
+
"NOTFOUND"
|
|
180
|
+
)
|
|
181
|
+
)`;
|
|
182
|
+
try {
|
|
183
|
+
const result = await cad.sendCommandWithResult(code);
|
|
184
|
+
if (result === 'UPDATED' || result === '"UPDATED"') {
|
|
185
|
+
return { content: [{ type: 'text', text: `已设置属性 ${tag} = ${value}` }] };
|
|
186
|
+
}
|
|
187
|
+
return { content: [{ type: 'text', text: `设置失败: ${result}` }], isError: true };
|
|
188
|
+
} catch (e) {
|
|
189
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export async function zoomToExtents() {
|
|
194
|
+
if (!cad.connected) { await cad.connect(); }
|
|
195
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
196
|
+
|
|
197
|
+
const code = `(progn
|
|
198
|
+
(vl-load-com)
|
|
199
|
+
(command "._ZOOM" "E")
|
|
200
|
+
"DONE"
|
|
201
|
+
)`;
|
|
202
|
+
try {
|
|
203
|
+
await cad.sendCommand(code + '\n');
|
|
204
|
+
return { content: [{ type: 'text', text: '已缩放到图形范围' }] };
|
|
205
|
+
} catch (e) {
|
|
206
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export async function zoomToWindow(p1, p2) {
|
|
211
|
+
if (!cad.connected) { await cad.connect(); }
|
|
212
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
213
|
+
|
|
214
|
+
const code = `(command "._ZOOM" "W" (list ${toSafePoint(p1)}) (list ${toSafePoint(p2)}))`;
|
|
215
|
+
try {
|
|
216
|
+
await cad.sendCommand(code + '\n');
|
|
217
|
+
return { content: [{ type: 'text', text: '已缩放到窗口' }] };
|
|
218
|
+
} catch (e) {
|
|
219
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export async function createNamedView(viewName, center = null) {
|
|
224
|
+
if (!cad.connected) { await cad.connect(); }
|
|
225
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
226
|
+
|
|
227
|
+
const code = center
|
|
228
|
+
? `(command ".-VIEW" "S" "${escapeLispString(viewName)}" "C" (list ${toSafePoint(center)}))`
|
|
229
|
+
: `(command ".-VIEW" "S" "${escapeLispString(viewName)}")`;
|
|
230
|
+
try {
|
|
231
|
+
await cad.sendCommand(code + '\n');
|
|
232
|
+
return { content: [{ type: 'text', text: `已创建命名视图: ${viewName}` }] };
|
|
233
|
+
} catch (e) {
|
|
234
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export async function restoreNamedView(viewName) {
|
|
239
|
+
if (!cad.connected) { await cad.connect(); }
|
|
240
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
241
|
+
|
|
242
|
+
const code = `(command ".-VIEW" "R" "${escapeLispString(viewName)}")`;
|
|
243
|
+
try {
|
|
244
|
+
await cad.sendCommand(code + '\n');
|
|
245
|
+
return { content: [{ type: 'text', text: `已恢复视图: ${viewName}` }] };
|
|
246
|
+
} catch (e) {
|
|
247
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export async function listNamedViews() {
|
|
252
|
+
if (!cad.connected) { await cad.connect(); }
|
|
253
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
254
|
+
|
|
255
|
+
const code = `(progn
|
|
256
|
+
(vl-load-com)
|
|
257
|
+
(setq views nil)
|
|
258
|
+
(while (setq v (tblnext "VIEW" (null views)))
|
|
259
|
+
(setq views (cons (cdr (assoc 2 v)) views))
|
|
260
|
+
)
|
|
261
|
+
(reverse views)
|
|
262
|
+
)`;
|
|
263
|
+
try {
|
|
264
|
+
const result = await cad.sendCommandWithResult(code);
|
|
265
|
+
return { content: [{ type: 'text', text: result || '无命名视图' }] };
|
|
266
|
+
} catch (e) {
|
|
267
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export async function exportDxf(outputPath, version = 'R2018') {
|
|
272
|
+
if (!cad.connected) { await cad.connect(); }
|
|
273
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
274
|
+
|
|
275
|
+
const versionMap = {
|
|
276
|
+
'R2018': 'AC1027', 'R2015': 'AC1024', 'R2013': 'AC1021',
|
|
277
|
+
'R2010': 'AC1018', 'R2007': 'AC1015', 'R2004': 'AC1012',
|
|
278
|
+
'R2000': 'AC1009'
|
|
279
|
+
};
|
|
280
|
+
const dxfVersion = versionMap[version] || 'AC1027';
|
|
281
|
+
|
|
282
|
+
const code = `(progn
|
|
283
|
+
(vl-load-com)
|
|
284
|
+
(vla-saveas (vla-get-activedocument (vlax-get-acad-object)) "${escapeLispString(outputPath)}" "${dxfVersion}")
|
|
285
|
+
"EXPORTED"
|
|
286
|
+
)`;
|
|
287
|
+
try {
|
|
288
|
+
const result = await cad.sendCommandWithResult(code);
|
|
289
|
+
if (result === 'EXPORTED' || result === '"EXPORTED"') {
|
|
290
|
+
return { content: [{ type: 'text', text: `已导出 DXF: ${outputPath}` }] };
|
|
291
|
+
}
|
|
292
|
+
return { content: [{ type: 'text', text: `导出失败: ${result}` }], isError: true };
|
|
293
|
+
} catch (e) {
|
|
294
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export async function exportDwf(outputPath) {
|
|
299
|
+
if (!cad.connected) { await cad.connect(); }
|
|
300
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
301
|
+
|
|
302
|
+
const code = `(progn
|
|
303
|
+
(vl-load-com)
|
|
304
|
+
(vla-export (vla-get-activedocument (vlax-get-acad-object)) "${escapeLispString(outputPath)}" "dwf")
|
|
305
|
+
"EXPORTED"
|
|
306
|
+
)`;
|
|
307
|
+
try {
|
|
308
|
+
const result = await cad.sendCommandWithResult(code);
|
|
309
|
+
if (result === 'EXPORTED' || result === '"EXPORTED"') {
|
|
310
|
+
return { content: [{ type: 'text', text: `已导出 DWF: ${outputPath}` }] };
|
|
311
|
+
}
|
|
312
|
+
return { content: [{ type: 'text', text: `导出失败: ${result}` }], isError: true };
|
|
313
|
+
} catch (e) {
|
|
314
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export async function batchSetLayer(handles, layerName) {
|
|
319
|
+
if (!cad.connected) { await cad.connect(); }
|
|
320
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
321
|
+
|
|
322
|
+
if (!Array.isArray(handles) || handles.length === 0) {
|
|
323
|
+
return { content: [{ type: 'text', text: '句柄列表为空' }], isError: true };
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const handlesStr = handles.map(h => `"${escapeLispString(h)}"`).join(' ');
|
|
327
|
+
const code = `(progn
|
|
328
|
+
(vl-load-com)
|
|
329
|
+
(setq ss (ssadd))
|
|
330
|
+
${handlesStr.split('\n').map(h => `(ssadd (handent ${h}) ss)`).join('\n')}
|
|
331
|
+
(command "._CHPROP" ss "" "LA" "${escapeLispString(layerName)}" "")
|
|
332
|
+
(strcat "Updated " (itoa ${handles.length}) " entities")
|
|
333
|
+
)`;
|
|
334
|
+
try {
|
|
335
|
+
const result = await cad.sendCommandWithResult(code);
|
|
336
|
+
return { content: [{ type: 'text', text: result || `已批量设置 ${handles.length} 个实体图层为 ${layerName}` }] };
|
|
337
|
+
} catch (e) {
|
|
338
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
339
|
+
}
|
|
340
|
+
}
|