forgecad 0.9.13 → 0.9.14
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/assets/{AdminPage-DramHHDf.js → AdminPage-eWGs2K6H.js} +1 -1
- package/dist/assets/{BenchmarkPage-Bjgkh5m9.js → BenchmarkPage-CTrLKfpo.js} +1 -1
- package/dist/assets/{BlogPage-n_HGP3Qm.js → BlogPage-5nPesyds.js} +1 -1
- package/dist/assets/{DocsPage-WCIkPmzC.js → DocsPage-C4Y3nbYc.js} +1 -1
- package/dist/assets/{EditorApp-CP9Za6tm.js → EditorApp-lXv53A1m.js} +9 -29
- package/dist/assets/{EmbedViewer-DEZKqdfW.js → EmbedViewer-C8fB4n5U.js} +2 -2
- package/dist/assets/{LandingPageProofDriven-CeRIctuj.js → LandingPageProofDriven-jSz0LaMM.js} +1 -1
- package/dist/assets/{PricingPage-rIRa8p4Y.js → PricingPage-B83B90zh.js} +1 -1
- package/dist/assets/{SettingsPage-BqCUvEXM.js → SettingsPage-DY889pcu.js} +1 -1
- package/dist/assets/{app-BUZqJvSO.js → app-bEww1ic4.js} +26 -28
- package/dist/assets/cli/{render-lhGxj50Y.js → render-Cho2uKG_.js} +88 -25
- package/dist/assets/{constructionHistoryWorker-ipD1jcIv.js → constructionHistoryWorker-HYwzJY4m.js} +1 -1
- package/dist/assets/{evalWorker-CHXSe_-u.js → evalWorker-CjQwJSE-.js} +3 -3
- package/dist/assets/{forgecad_geometry-BVnIeXMG.js → forgecad_geometry-CH2nvuLA.js} +1 -1
- package/dist/assets/forgecad_geometry_bg-C5_E9Oa9.wasm +0 -0
- package/dist/assets/{manifold-D1LZIHqn.js → manifold-CG9Fokx-.js} +1 -1
- package/dist/assets/{manifold-BTkzxi9V.js → manifold-rmfAcdwF.js} +1 -1
- package/dist/assets/{manifold-C2fwoTgd.js → manifold-uRzgk5O8.js} +2 -2
- package/dist/assets/{reportWorker-Cq1qGmg0.js → reportWorker-4cW_ZpoS.js} +3 -3
- package/dist/assets/{scalar-sampling-budget-D9Qv_UlJ.js → scalar-sampling-budget-CfDiFvh7.js} +12 -18
- package/dist/assets/{solver-BZ9LPTHs.js → solver-DuJAO8S6.js} +1 -1
- package/dist/assets/solver_bg-CWvv4lnN.wasm +0 -0
- package/dist/assets/{renderSceneState-Dr0xPq1A.js → targets-D6PWsv6X.js} +27 -1
- package/dist/cli/render.html +1 -1
- package/dist/docs/index.html +2 -2
- package/dist/docs-raw/AI/usage.md +6 -5
- package/dist/docs-raw/CLI.md +41 -11
- package/dist/docs-raw/generated/concepts.md +3 -3
- package/dist/docs-raw/generated/viewport.md +3 -3
- package/dist/docs-raw/harbor-cli.md +854 -0
- package/dist/docs-raw/rl-environments.md +100 -258
- package/dist/docs-raw/skills/forgecad-3d-reconstruction.md +2 -2
- package/dist/docs-raw/skills/forgecad-make-a-model.md +3 -3
- package/dist/docs-raw/skills/forgecad-reconstruction-benchmark.md +3 -3
- package/dist/index.html +1 -1
- package/dist/sitemap.xml +7 -7
- package/dist-cli/{check-compiler-LOXCPEOI.js → check-compiler-U5SOPN7X.js} +2 -2
- package/dist-cli/{check-query-propagation-BAKNVWXR.js → check-query-propagation-XOKNSSYU.js} +2 -2
- package/dist-cli/{chunk-RY43WF46.js → chunk-EXWGNL6K.js} +342 -2
- package/dist-cli/{chunk-RY43WF46.js.map → chunk-EXWGNL6K.js.map} +1 -1
- package/dist-cli/forgecad.js +733 -352
- package/dist-cli/forgecad.js.map +1 -1
- package/dist-cli/forgecad_geometry_bg.wasm +0 -0
- package/dist-cli/solver_bg.wasm +0 -0
- package/dist-skill/CONTEXT.md +3 -3
- package/dist-skill/docs/CLI.md +41 -11
- package/dist-skill/docs/generated/viewport.md +3 -3
- package/dist-skill/docs-dev/CLI.md +41 -11
- package/dist-skill/docs-dev/generated/viewport.md +3 -3
- package/dist-skill/library/forgecad-3d-reconstruction/SKILL.md +2 -2
- package/dist-skill/library/forgecad-make-a-model/SKILL.md +3 -3
- package/dist-skill/library/forgecad-reconstruction-benchmark/SKILL.md +3 -3
- package/package.json +1 -6
- package/dist/assets/forgecad_geometry_bg-DufhhCBV.wasm +0 -0
- package/dist/assets/solver_bg-DAHZJ_rw.wasm +0 -0
- /package/dist-cli/{check-compiler-LOXCPEOI.js.map → check-compiler-U5SOPN7X.js.map} +0 -0
- /package/dist-cli/{check-query-propagation-BAKNVWXR.js.map → check-query-propagation-XOKNSSYU.js.map} +0 -0
package/dist-cli/forgecad.js
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
CLI_DEFAULT_BACKEND,
|
|
5
5
|
COMPILER_REGRESSION_CORPUS,
|
|
6
6
|
FILLET_EDGE_WORKFLOW_CODE,
|
|
7
|
+
MathUtils,
|
|
7
8
|
OCCTUnsupportedError,
|
|
8
9
|
Rectangle2D,
|
|
9
10
|
Sculpt,
|
|
@@ -11,6 +12,7 @@ import {
|
|
|
11
12
|
Shape,
|
|
12
13
|
ShapeGroup,
|
|
13
14
|
Transform,
|
|
15
|
+
Vector3,
|
|
14
16
|
activateBackend,
|
|
15
17
|
addPolygon,
|
|
16
18
|
addRect,
|
|
@@ -119,7 +121,7 @@ import {
|
|
|
119
121
|
union2d,
|
|
120
122
|
updateConstraintValue,
|
|
121
123
|
wrapOCCTShapeBackend
|
|
122
|
-
} from "./chunk-
|
|
124
|
+
} from "./chunk-EXWGNL6K.js";
|
|
123
125
|
|
|
124
126
|
// cli/forgecad.ts
|
|
125
127
|
import { Command, Flags, Help, flush as flushOclif, handle as handleOclif, run as runOclif } from "@oclif/core";
|
|
@@ -7141,7 +7143,7 @@ var RENDER_STYLES = new Set(RENDER_STYLE_NAMES);
|
|
|
7141
7143
|
var RENDER_STYLE_LABEL = RENDER_STYLE_NAMES.join("|");
|
|
7142
7144
|
var SCAN_GRANULARITY_MIN = 12;
|
|
7143
7145
|
var SCAN_GRANULARITY_DEFAULT = 32;
|
|
7144
|
-
var SCAN_GRANULARITY_MAX =
|
|
7146
|
+
var SCAN_GRANULARITY_MAX = 144;
|
|
7145
7147
|
var COMPARISON_VIEW_MODES = /* @__PURE__ */ new Set(["difference-only"]);
|
|
7146
7148
|
function evidenceNameForChannel(channel) {
|
|
7147
7149
|
return INSPECT_EVIDENCE_BY_CHANNEL.get(channel)?.name ?? channel;
|
|
@@ -19106,6 +19108,281 @@ async function runGcodeExportCli(argv) {
|
|
|
19106
19108
|
console.log(` Bounds: [${tp.bounds.min.map((v) => v.toFixed(1)).join(", ")}] \u2192 [${tp.bounds.max.map((v) => v.toFixed(1)).join(", ")}]`);
|
|
19107
19109
|
}
|
|
19108
19110
|
|
|
19111
|
+
// src/forge/targets.ts
|
|
19112
|
+
var cleanSceneTargetPathSegments = (segments) => (segments ?? []).map((segment) => segment.trim()).filter((segment) => segment.length > 0);
|
|
19113
|
+
function getSceneObjectTreePath(object) {
|
|
19114
|
+
const explicitTreePath = cleanSceneTargetPathSegments(object.treePath);
|
|
19115
|
+
if (explicitTreePath.length > 0) return explicitTreePath;
|
|
19116
|
+
const name = object.name.trim() || object.id;
|
|
19117
|
+
const groupName = object.groupName?.trim();
|
|
19118
|
+
if (!groupName) return [name];
|
|
19119
|
+
const groupPath = groupName.split(".").map((segment) => segment.trim()).filter((segment) => segment.length > 0);
|
|
19120
|
+
const prefixedLeaf = `${groupName}.`;
|
|
19121
|
+
if (name.startsWith(prefixedLeaf)) {
|
|
19122
|
+
const leafName = name.slice(prefixedLeaf.length).trim();
|
|
19123
|
+
return [...groupPath, leafName || name];
|
|
19124
|
+
}
|
|
19125
|
+
return [...groupPath, name];
|
|
19126
|
+
}
|
|
19127
|
+
function getSceneObjectKind(object) {
|
|
19128
|
+
if (object.mock) return "mock";
|
|
19129
|
+
if (object.sketch) return "sketch";
|
|
19130
|
+
if (object.toolpath) return "toolpath";
|
|
19131
|
+
if (object.sdf) return "sdf";
|
|
19132
|
+
if (object.shape) return "shape";
|
|
19133
|
+
return "object";
|
|
19134
|
+
}
|
|
19135
|
+
function buildSceneTargetEntries(objects) {
|
|
19136
|
+
return objects.map((object) => {
|
|
19137
|
+
const pathSegments = getSceneObjectTreePath(object);
|
|
19138
|
+
return {
|
|
19139
|
+
id: object.id,
|
|
19140
|
+
name: object.name,
|
|
19141
|
+
kind: getSceneObjectKind(object),
|
|
19142
|
+
pathSegments,
|
|
19143
|
+
path: pathSegments.join("/"),
|
|
19144
|
+
dottedPath: pathSegments.join("."),
|
|
19145
|
+
group: object.groupName?.trim() || void 0,
|
|
19146
|
+
tags: object.tags ?? [],
|
|
19147
|
+
mock: object.mock === true,
|
|
19148
|
+
object
|
|
19149
|
+
};
|
|
19150
|
+
});
|
|
19151
|
+
}
|
|
19152
|
+
function formatSceneTargetPath(entry) {
|
|
19153
|
+
return entry.path || entry.name;
|
|
19154
|
+
}
|
|
19155
|
+
function resolveSceneTargets(entries, selector) {
|
|
19156
|
+
const needle = normalizeTargetText(selector);
|
|
19157
|
+
if (!needle) throw new Error("Target selector must not be empty.");
|
|
19158
|
+
const hasGlob = /[*?]/.test(selector);
|
|
19159
|
+
if (hasGlob) {
|
|
19160
|
+
const pattern = globToRegExp(needle);
|
|
19161
|
+
const matches = entries.filter((entry) => targetCandidateTexts(entry).some((candidate) => pattern.test(candidate)));
|
|
19162
|
+
if (matches.length > 0) return matches;
|
|
19163
|
+
throw targetNotFound(selector, entries);
|
|
19164
|
+
}
|
|
19165
|
+
const idMatches = entries.filter((entry) => normalizeTargetText(entry.id) === needle);
|
|
19166
|
+
if (idMatches.length > 0) return idMatches;
|
|
19167
|
+
const exactPathMatches = entries.filter(
|
|
19168
|
+
(entry) => normalizeTargetText(entry.path) === needle || normalizeTargetText(entry.dottedPath) === needle
|
|
19169
|
+
);
|
|
19170
|
+
if (exactPathMatches.length > 0) return exactPathMatches;
|
|
19171
|
+
const groupMatches = entries.filter((entry) => {
|
|
19172
|
+
const groupPath = entry.pathSegments.slice(0, -1);
|
|
19173
|
+
return normalizeTargetText(groupPath.join("/")) === needle || normalizeTargetText(groupPath.join(".")) === needle;
|
|
19174
|
+
});
|
|
19175
|
+
if (groupMatches.length > 0) return groupMatches;
|
|
19176
|
+
const nameMatches2 = entries.filter(
|
|
19177
|
+
(entry) => normalizeTargetText(entry.name) === needle || normalizeTargetText(entry.pathSegments[entry.pathSegments.length - 1] ?? "") === needle
|
|
19178
|
+
);
|
|
19179
|
+
if (nameMatches2.length === 1) return nameMatches2;
|
|
19180
|
+
if (nameMatches2.length > 1) throw ambiguousTarget(selector, nameMatches2);
|
|
19181
|
+
throw targetNotFound(selector, entries);
|
|
19182
|
+
}
|
|
19183
|
+
function suggestSceneTargets(selector, entries, limit = 8) {
|
|
19184
|
+
const needle = normalizeTargetText(selector);
|
|
19185
|
+
if (!needle) return entries.slice(0, limit);
|
|
19186
|
+
return entries.map((entry) => ({ entry, score: scoreTarget(entry, needle) })).filter((ranked) => ranked.score > 0).sort((a, b) => b.score - a.score || a.entry.path.localeCompare(b.entry.path)).slice(0, limit).map((ranked) => ranked.entry);
|
|
19187
|
+
}
|
|
19188
|
+
function targetCandidateTexts(entry) {
|
|
19189
|
+
return [
|
|
19190
|
+
entry.id,
|
|
19191
|
+
entry.name,
|
|
19192
|
+
entry.path,
|
|
19193
|
+
entry.dottedPath,
|
|
19194
|
+
entry.group ?? "",
|
|
19195
|
+
entry.pathSegments[entry.pathSegments.length - 1] ?? ""
|
|
19196
|
+
].map(normalizeTargetText);
|
|
19197
|
+
}
|
|
19198
|
+
function normalizeTargetText(value) {
|
|
19199
|
+
return value.trim().replace(/\\/g, "/").replace(/\s*\/\s*/g, "/").replace(/\s*\.\s*/g, ".").toLowerCase();
|
|
19200
|
+
}
|
|
19201
|
+
function globToRegExp(value) {
|
|
19202
|
+
const escaped = value.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
19203
|
+
return new RegExp(`^${escaped}$`, "i");
|
|
19204
|
+
}
|
|
19205
|
+
function scoreTarget(entry, needle) {
|
|
19206
|
+
const candidates = targetCandidateTexts(entry);
|
|
19207
|
+
if (candidates.some((candidate) => candidate === needle)) return 100;
|
|
19208
|
+
if (candidates.some((candidate) => candidate.startsWith(needle))) return 60;
|
|
19209
|
+
if (candidates.some((candidate) => candidate.includes(needle))) return 30;
|
|
19210
|
+
const tokens = needle.split(/[\s/._-]+/).filter(Boolean);
|
|
19211
|
+
if (tokens.length > 0 && tokens.every((token) => candidates.some((candidate) => candidate.includes(token)))) return 15;
|
|
19212
|
+
return 0;
|
|
19213
|
+
}
|
|
19214
|
+
function targetSummary(entry) {
|
|
19215
|
+
return `${formatSceneTargetPath(entry)} (${entry.kind}, ${entry.id})`;
|
|
19216
|
+
}
|
|
19217
|
+
function targetNotFound(selector, entries) {
|
|
19218
|
+
const suggestions = suggestSceneTargets(selector, entries);
|
|
19219
|
+
const detail = suggestions.length > 0 ? `
|
|
19220
|
+
Did you mean:
|
|
19221
|
+
${suggestions.map((entry) => ` ${targetSummary(entry)}`).join("\n")}` : "";
|
|
19222
|
+
return new Error(`Target "${selector}" matched no scene objects.${detail}`);
|
|
19223
|
+
}
|
|
19224
|
+
function ambiguousTarget(selector, matches) {
|
|
19225
|
+
return new Error(
|
|
19226
|
+
`Target "${selector}" is ambiguous.
|
|
19227
|
+
Use a full path:
|
|
19228
|
+
${matches.map((entry) => ` ${targetSummary(entry)}`).join("\n")}`
|
|
19229
|
+
);
|
|
19230
|
+
}
|
|
19231
|
+
|
|
19232
|
+
// cli/forge-ls.ts
|
|
19233
|
+
var TARGET_KINDS = ["shape", "sketch", "sdf", "toolpath", "mock", "object"];
|
|
19234
|
+
function usage12() {
|
|
19235
|
+
return [
|
|
19236
|
+
"Usage: forgecad ls <model.forge.js|asset.stl|asset.obj|asset.3mf|asset.step|asset.stp> [target] [--tree] [--long] [--json] [--kind shape,sketch,mock] [--param Key=Value] [--backend manifold|occt|truck] [--quality live|default|high]"
|
|
19237
|
+
].join("\n");
|
|
19238
|
+
}
|
|
19239
|
+
function parseKindFilter(raw) {
|
|
19240
|
+
const values = raw.split(",").map((value) => value.trim()).filter(Boolean);
|
|
19241
|
+
const kinds = /* @__PURE__ */ new Set();
|
|
19242
|
+
for (const value of values) {
|
|
19243
|
+
if (!TARGET_KINDS.includes(value)) {
|
|
19244
|
+
throw new Error(`Invalid --kind value: ${value}. Expected one of ${TARGET_KINDS.join(", ")}.`);
|
|
19245
|
+
}
|
|
19246
|
+
kinds.add(value);
|
|
19247
|
+
}
|
|
19248
|
+
if (kinds.size === 0) throw new Error("--kind requires at least one kind.");
|
|
19249
|
+
return kinds;
|
|
19250
|
+
}
|
|
19251
|
+
function parseLsOptions(argv) {
|
|
19252
|
+
if (argv.length === 0 || argv.includes("-h") || argv.includes("--help")) {
|
|
19253
|
+
console.log(usage12());
|
|
19254
|
+
process.exit(0);
|
|
19255
|
+
}
|
|
19256
|
+
const { overrides: _paramOverrides, consumed: paramConsumed } = parseParamFlags(argv);
|
|
19257
|
+
const { backend, consumed: backendConsumed } = parseBackendArg(argv);
|
|
19258
|
+
const { quality, consumed: qualityConsumed } = parseQualityArg(argv);
|
|
19259
|
+
const consumed = /* @__PURE__ */ new Set([...paramConsumed, ...backendConsumed, ...qualityConsumed]);
|
|
19260
|
+
let json = false;
|
|
19261
|
+
let compact = false;
|
|
19262
|
+
let tree = false;
|
|
19263
|
+
let long = false;
|
|
19264
|
+
let kinds = null;
|
|
19265
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
19266
|
+
if (consumed.has(i)) continue;
|
|
19267
|
+
const arg = argv[i];
|
|
19268
|
+
if (arg === "--json") {
|
|
19269
|
+
json = true;
|
|
19270
|
+
consumed.add(i);
|
|
19271
|
+
} else if (arg === "--compact") {
|
|
19272
|
+
compact = true;
|
|
19273
|
+
consumed.add(i);
|
|
19274
|
+
} else if (arg === "--tree") {
|
|
19275
|
+
tree = true;
|
|
19276
|
+
consumed.add(i);
|
|
19277
|
+
} else if (arg === "--long") {
|
|
19278
|
+
long = true;
|
|
19279
|
+
consumed.add(i);
|
|
19280
|
+
} else if (arg === "--kind") {
|
|
19281
|
+
const raw = argv[i + 1];
|
|
19282
|
+
if (!raw || raw.startsWith("--")) throw new Error("--kind requires a comma-separated value.");
|
|
19283
|
+
kinds = parseKindFilter(raw);
|
|
19284
|
+
consumed.add(i);
|
|
19285
|
+
consumed.add(i + 1);
|
|
19286
|
+
i += 1;
|
|
19287
|
+
} else if (arg.startsWith("--")) {
|
|
19288
|
+
throw new Error(`Unknown option: ${arg}`);
|
|
19289
|
+
}
|
|
19290
|
+
}
|
|
19291
|
+
const positionals = argv.filter((_, index) => !consumed.has(index));
|
|
19292
|
+
if (!positionals[0]) throw new Error("Missing input path.");
|
|
19293
|
+
if (positionals.length > 2) throw new Error(`Unexpected argument: ${positionals[2]}`);
|
|
19294
|
+
return { scriptPath: positionals[0], selector: positionals[1], json, compact, tree, long, kinds, backend, quality, consumed };
|
|
19295
|
+
}
|
|
19296
|
+
function filteredTargets(entries, options) {
|
|
19297
|
+
let targets = options.selector ? resolveSceneTargets(entries, options.selector) : entries;
|
|
19298
|
+
if (options.kinds) targets = targets.filter((entry) => options.kinds?.has(entry.kind));
|
|
19299
|
+
return targets;
|
|
19300
|
+
}
|
|
19301
|
+
function formatNumber(value, digits = 1) {
|
|
19302
|
+
if (!Number.isFinite(value)) return String(value);
|
|
19303
|
+
return value.toFixed(digits).replace(/\.0$/, "");
|
|
19304
|
+
}
|
|
19305
|
+
function formatBounds(min, max) {
|
|
19306
|
+
return `[${min.map((v) => formatNumber(v)).join(",")}]..[${max.map((v) => formatNumber(v)).join(",")}]`;
|
|
19307
|
+
}
|
|
19308
|
+
function targetMetrics(entry) {
|
|
19309
|
+
const object = entry.object;
|
|
19310
|
+
if (object.shape) {
|
|
19311
|
+
const bounds2 = object.shape.boundingBox();
|
|
19312
|
+
return {
|
|
19313
|
+
volume: object.shape.volume(),
|
|
19314
|
+
triangles: object.shape.numTri(),
|
|
19315
|
+
bodies: object.shape.numBodies(),
|
|
19316
|
+
bounds: { min: bounds2.min, max: bounds2.max }
|
|
19317
|
+
};
|
|
19318
|
+
}
|
|
19319
|
+
if (object.sketch) return { area: object.sketch.area(), regions: object.sketch.regions().length };
|
|
19320
|
+
if (object.sdf) return { bounds: object.sdf.bounds };
|
|
19321
|
+
return null;
|
|
19322
|
+
}
|
|
19323
|
+
function targetJson(entry, includeMetrics) {
|
|
19324
|
+
return {
|
|
19325
|
+
id: entry.id,
|
|
19326
|
+
path: entry.path,
|
|
19327
|
+
name: entry.name,
|
|
19328
|
+
kind: entry.kind,
|
|
19329
|
+
group: entry.group ?? null,
|
|
19330
|
+
tags: entry.tags,
|
|
19331
|
+
mock: entry.mock,
|
|
19332
|
+
...includeMetrics ? { metrics: targetMetrics(entry) } : {}
|
|
19333
|
+
};
|
|
19334
|
+
}
|
|
19335
|
+
function printLineList(entries, long) {
|
|
19336
|
+
for (const entry of entries) {
|
|
19337
|
+
const base = `${entry.kind.padEnd(8)} ${formatSceneTargetPath(entry)}`;
|
|
19338
|
+
if (!long) {
|
|
19339
|
+
console.log(base);
|
|
19340
|
+
continue;
|
|
19341
|
+
}
|
|
19342
|
+
const metrics = targetMetrics(entry);
|
|
19343
|
+
const detail = metrics && "volume" in metrics ? ` id=${entry.id} vol=${formatNumber(metrics.volume)} tris=${metrics.triangles.toLocaleString()} bodies=${metrics.bodies} bbox=${formatBounds(metrics.bounds.min, metrics.bounds.max)}` : metrics && "area" in metrics ? ` id=${entry.id} area=${formatNumber(metrics.area)} regions=${metrics.regions}` : ` id=${entry.id}`;
|
|
19344
|
+
console.log(`${base}${detail}`);
|
|
19345
|
+
}
|
|
19346
|
+
}
|
|
19347
|
+
function printTree(entries) {
|
|
19348
|
+
const printedGroups = /* @__PURE__ */ new Set();
|
|
19349
|
+
for (const entry of entries) {
|
|
19350
|
+
for (let depth = 1; depth < entry.pathSegments.length; depth += 1) {
|
|
19351
|
+
const groupPath = entry.pathSegments.slice(0, depth).join("/");
|
|
19352
|
+
if (printedGroups.has(groupPath)) continue;
|
|
19353
|
+
printedGroups.add(groupPath);
|
|
19354
|
+
console.log(`${" ".repeat(depth - 1)}${entry.pathSegments[depth - 1]}/`);
|
|
19355
|
+
}
|
|
19356
|
+
const indent = " ".repeat(Math.max(0, entry.pathSegments.length - 1));
|
|
19357
|
+
const label = entry.pathSegments[entry.pathSegments.length - 1] ?? entry.name;
|
|
19358
|
+
console.log(`${indent}${entry.kind.padEnd(8)} ${label}`);
|
|
19359
|
+
}
|
|
19360
|
+
}
|
|
19361
|
+
async function runLsCli(argv = process.argv.slice(2)) {
|
|
19362
|
+
let options;
|
|
19363
|
+
try {
|
|
19364
|
+
options = parseLsOptions(argv);
|
|
19365
|
+
} catch (error) {
|
|
19366
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
19367
|
+
console.error(usage12());
|
|
19368
|
+
process.exit(1);
|
|
19369
|
+
}
|
|
19370
|
+
const { overrides } = parseParamFlags(argv);
|
|
19371
|
+
const result = await runModelForInspect(options.scriptPath, options.backend, options.quality, overrides);
|
|
19372
|
+
if (result.error) {
|
|
19373
|
+
console.error("ERROR:", result.error);
|
|
19374
|
+
process.exit(1);
|
|
19375
|
+
}
|
|
19376
|
+
const entries = filteredTargets(buildSceneTargetEntries(result.objects), options);
|
|
19377
|
+
if (options.json) {
|
|
19378
|
+
const body = { script: options.scriptPath, count: entries.length, targets: entries.map((entry) => targetJson(entry, options.long)) };
|
|
19379
|
+
console.log(JSON.stringify(body, null, options.compact ? 0 : 2));
|
|
19380
|
+
return;
|
|
19381
|
+
}
|
|
19382
|
+
if (options.tree) printTree(entries);
|
|
19383
|
+
else printLineList(entries, options.long);
|
|
19384
|
+
}
|
|
19385
|
+
|
|
19109
19386
|
// cli/forge-mesh.ts
|
|
19110
19387
|
import { writeFileSync as writeFileSync7 } from "fs";
|
|
19111
19388
|
import { extname as extname6, resolve as resolve20 } from "path";
|
|
@@ -19409,6 +19686,74 @@ import { execSync as execSync2, spawnSync } from "child_process";
|
|
|
19409
19686
|
import { tmpdir as tmpdir2 } from "os";
|
|
19410
19687
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
19411
19688
|
|
|
19689
|
+
// cli/framing-diagnostics.ts
|
|
19690
|
+
var DEFAULT_PERSPECTIVE_FIT_MARGIN = 1.1;
|
|
19691
|
+
var DEFAULT_MIN_CAMERA_DISTANCE = 1;
|
|
19692
|
+
function bboxCorners(bbox) {
|
|
19693
|
+
const [minX, minY, minZ] = bbox.min;
|
|
19694
|
+
const [maxX, maxY, maxZ] = bbox.max;
|
|
19695
|
+
return [
|
|
19696
|
+
new Vector3(minX, minY, minZ),
|
|
19697
|
+
new Vector3(minX, minY, maxZ),
|
|
19698
|
+
new Vector3(minX, maxY, minZ),
|
|
19699
|
+
new Vector3(minX, maxY, maxZ),
|
|
19700
|
+
new Vector3(maxX, minY, minZ),
|
|
19701
|
+
new Vector3(maxX, minY, maxZ),
|
|
19702
|
+
new Vector3(maxX, maxY, minZ),
|
|
19703
|
+
new Vector3(maxX, maxY, maxZ)
|
|
19704
|
+
];
|
|
19705
|
+
}
|
|
19706
|
+
function bboxCenter(bbox) {
|
|
19707
|
+
return new Vector3((bbox.min[0] + bbox.max[0]) * 0.5, (bbox.min[1] + bbox.max[1]) * 0.5, (bbox.min[2] + bbox.max[2]) * 0.5);
|
|
19708
|
+
}
|
|
19709
|
+
function finitePositive(value, label) {
|
|
19710
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
19711
|
+
throw new Error(`${label} must be a positive finite number.`);
|
|
19712
|
+
}
|
|
19713
|
+
return value;
|
|
19714
|
+
}
|
|
19715
|
+
function cameraRightFor(backward, up) {
|
|
19716
|
+
const normalizedUp = up.lengthSq() > 1e-8 ? up.clone().normalize() : new Vector3(0, 0, 1);
|
|
19717
|
+
let right = new Vector3().crossVectors(normalizedUp, backward);
|
|
19718
|
+
if (right.lengthSq() > 1e-8) return right.normalize();
|
|
19719
|
+
const fallbackUp = Math.abs(backward.z) > 0.92 ? new Vector3(0, 1, 0) : new Vector3(0, 0, 1);
|
|
19720
|
+
right = new Vector3().crossVectors(fallbackUp, backward);
|
|
19721
|
+
if (right.lengthSq() > 1e-8) return right.normalize();
|
|
19722
|
+
return new Vector3(1, 0, 0);
|
|
19723
|
+
}
|
|
19724
|
+
function perspectiveCameraDistanceForBounds(bbox, directionFromTargetToCamera, options) {
|
|
19725
|
+
const backward = new Vector3(...directionFromTargetToCamera);
|
|
19726
|
+
if (backward.lengthSq() <= 1e-8) {
|
|
19727
|
+
throw new Error("directionFromTargetToCamera must be a non-zero vector.");
|
|
19728
|
+
}
|
|
19729
|
+
backward.normalize();
|
|
19730
|
+
const fovDeg = finitePositive(options.fovDeg, "fovDeg");
|
|
19731
|
+
if (fovDeg >= 180) {
|
|
19732
|
+
throw new Error("fovDeg must be less than 180 degrees.");
|
|
19733
|
+
}
|
|
19734
|
+
const aspect = finitePositive(options.aspect ?? 1, "aspect");
|
|
19735
|
+
const margin = finitePositive(options.margin ?? DEFAULT_PERSPECTIVE_FIT_MARGIN, "margin");
|
|
19736
|
+
const minDistance = finitePositive(options.minDistance ?? DEFAULT_MIN_CAMERA_DISTANCE, "minDistance");
|
|
19737
|
+
const tanHalfVerticalFov = Math.tan(MathUtils.degToRad(fovDeg) * 0.5);
|
|
19738
|
+
const tanHalfHorizontalFov = tanHalfVerticalFov * aspect;
|
|
19739
|
+
const right = cameraRightFor(backward, new Vector3(...options.up ?? [0, 0, 1]));
|
|
19740
|
+
const screenUp = new Vector3().crossVectors(backward, right).normalize();
|
|
19741
|
+
const center = bboxCenter(bbox);
|
|
19742
|
+
let requiredDistance = minDistance;
|
|
19743
|
+
for (const corner of bboxCorners(bbox)) {
|
|
19744
|
+
const offset = corner.sub(center);
|
|
19745
|
+
const depthOffset = offset.dot(backward);
|
|
19746
|
+
const horizontalOffset = Math.abs(offset.dot(right));
|
|
19747
|
+
const verticalOffset = Math.abs(offset.dot(screenUp));
|
|
19748
|
+
requiredDistance = Math.max(
|
|
19749
|
+
requiredDistance,
|
|
19750
|
+
horizontalOffset * margin / tanHalfHorizontalFov + depthOffset,
|
|
19751
|
+
verticalOffset * margin / tanHalfVerticalFov + depthOffset
|
|
19752
|
+
);
|
|
19753
|
+
}
|
|
19754
|
+
return requiredDistance;
|
|
19755
|
+
}
|
|
19756
|
+
|
|
19412
19757
|
// cli/render-camera-tokens.ts
|
|
19413
19758
|
var CAMERA_TOKEN_DIRECTIONS = {
|
|
19414
19759
|
front: [0, -1, 0.2],
|
|
@@ -19442,17 +19787,13 @@ function parseCameraToken(token) {
|
|
|
19442
19787
|
`Unknown camera "${token}". Use a preset (front, back, side, right, top, iso) or azimuth:elevation in degrees (e.g. 45:30).`
|
|
19443
19788
|
);
|
|
19444
19789
|
}
|
|
19445
|
-
function cameraStateFromToken(token, center, defaultDistance, fov) {
|
|
19790
|
+
function cameraStateFromToken(token, center, defaultDistance, fov, bounds2) {
|
|
19446
19791
|
const parsed = parseCameraToken(token);
|
|
19447
19792
|
const dir = normalizeCameraDirection(parsed.dir);
|
|
19448
|
-
const distance2 = parsed.distance ?? defaultDistance;
|
|
19793
|
+
const distance2 = parsed.distance ?? (bounds2 ? perspectiveCameraDistanceForBounds(bounds2, dir, { fovDeg: fov }) : defaultDistance);
|
|
19449
19794
|
return {
|
|
19450
19795
|
projectionMode: "perspective",
|
|
19451
|
-
position: [
|
|
19452
|
-
center[0] + dir[0] * distance2,
|
|
19453
|
-
center[1] + dir[1] * distance2,
|
|
19454
|
-
center[2] + dir[2] * distance2
|
|
19455
|
-
],
|
|
19796
|
+
position: [center[0] + dir[0] * distance2, center[1] + dir[1] * distance2, center[2] + dir[2] * distance2],
|
|
19456
19797
|
target: center,
|
|
19457
19798
|
up: [0, 0, 1],
|
|
19458
19799
|
fov
|
|
@@ -19710,17 +20051,17 @@ function computeMeshCameraFrame(objects) {
|
|
|
19710
20051
|
const min = [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY];
|
|
19711
20052
|
const max = [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY];
|
|
19712
20053
|
for (const obj of objects) {
|
|
19713
|
-
const
|
|
20054
|
+
const bbox2 = obj.shape.boundingBox();
|
|
19714
20055
|
for (let axis = 0; axis < 3; axis += 1) {
|
|
19715
|
-
min[axis] = Math.min(min[axis],
|
|
19716
|
-
max[axis] = Math.max(max[axis],
|
|
20056
|
+
min[axis] = Math.min(min[axis], bbox2.min[axis]);
|
|
20057
|
+
max[axis] = Math.max(max[axis], bbox2.max[axis]);
|
|
19717
20058
|
}
|
|
19718
20059
|
}
|
|
19719
20060
|
const center = [(min[0] + max[0]) * 0.5, (min[1] + max[1]) * 0.5, (min[2] + max[2]) * 0.5];
|
|
19720
|
-
const maxDim = Math.max(1, max[0] - min[0], max[1] - min[1], max[2] - min[2]);
|
|
19721
20061
|
const fov = 45;
|
|
19722
|
-
const
|
|
19723
|
-
|
|
20062
|
+
const bbox = { min, max };
|
|
20063
|
+
const distance2 = perspectiveCameraDistanceForBounds(bbox, [0, -1, 0.32], { fovDeg: fov });
|
|
20064
|
+
return { center, distance: distance2, fov, bbox };
|
|
19724
20065
|
}
|
|
19725
20066
|
function sceneConfigCameraToViewportCamera(sceneConfig, frame) {
|
|
19726
20067
|
const camera = sceneConfig.camera;
|
|
@@ -19737,7 +20078,10 @@ function resolveHqCamera(args, sceneConfig, meshObjects) {
|
|
|
19737
20078
|
const frame = computeMeshCameraFrame(meshObjects);
|
|
19738
20079
|
if (args.scene?.camera) return args.scene.camera;
|
|
19739
20080
|
if (args.viewName) return resolveNamedSceneViewCamera(sceneConfig, args.viewName);
|
|
19740
|
-
if (args.cameraToken)
|
|
20081
|
+
if (args.cameraToken) {
|
|
20082
|
+
const fov = sceneConfig?.camera?.fov ?? frame.fov;
|
|
20083
|
+
return cameraStateFromToken(args.cameraToken, frame.center, frame.distance, fov, frame.bbox);
|
|
20084
|
+
}
|
|
19741
20085
|
if (sceneConfig) return sceneConfigCameraToViewportCamera(sceneConfig, frame);
|
|
19742
20086
|
return null;
|
|
19743
20087
|
}
|
|
@@ -19881,12 +20225,12 @@ import { basename as basename9, resolve as resolve23 } from "path";
|
|
|
19881
20225
|
function defaultPngOutput(scriptPath) {
|
|
19882
20226
|
return scriptPath.replace(/\.(forge|sketch)\.js$/, ".png").replace(/\.js$/, ".png");
|
|
19883
20227
|
}
|
|
19884
|
-
function
|
|
20228
|
+
function usage13() {
|
|
19885
20229
|
console.error("Usage: forgecad render sketch <script.forge.js> [output.png] [--size <px>] [--chrome-path <path>]");
|
|
19886
20230
|
process.exit(1);
|
|
19887
20231
|
}
|
|
19888
20232
|
function parseCli2(argv) {
|
|
19889
|
-
if (argv.length === 0 || argv.includes("-h") || argv.includes("--help"))
|
|
20233
|
+
if (argv.length === 0 || argv.includes("-h") || argv.includes("--help")) usage13();
|
|
19890
20234
|
let scriptPath;
|
|
19891
20235
|
let outputPath;
|
|
19892
20236
|
let size = 1024;
|
|
@@ -19911,7 +20255,7 @@ function parseCli2(argv) {
|
|
|
19911
20255
|
else if (!outputPath) outputPath = arg;
|
|
19912
20256
|
else throw new Error(`Unexpected argument: ${arg}`);
|
|
19913
20257
|
}
|
|
19914
|
-
if (!scriptPath)
|
|
20258
|
+
if (!scriptPath) usage13();
|
|
19915
20259
|
if (!Number.isFinite(size) || size < 128 || size > 4096) throw new Error(`--size must be between 128 and 4096 (got ${size})`);
|
|
19916
20260
|
return {
|
|
19917
20261
|
scriptPath,
|
|
@@ -19927,7 +20271,7 @@ async function runRender2dCli(argv = process.argv.slice(2)) {
|
|
|
19927
20271
|
options = parseCli2(argv);
|
|
19928
20272
|
} catch (err) {
|
|
19929
20273
|
console.error(String(err));
|
|
19930
|
-
|
|
20274
|
+
usage13();
|
|
19931
20275
|
}
|
|
19932
20276
|
const chromePath = findChromePath(options.chromePath);
|
|
19933
20277
|
if (!chromePath) {
|
|
@@ -20046,13 +20390,13 @@ function formatSheetCutList(input) {
|
|
|
20046
20390
|
}
|
|
20047
20391
|
|
|
20048
20392
|
// cli/forge-cut-list.ts
|
|
20049
|
-
function
|
|
20393
|
+
function usage14() {
|
|
20050
20394
|
console.error("Usage: forgecad cut-list <script.forge.js>");
|
|
20051
20395
|
process.exit(1);
|
|
20052
20396
|
}
|
|
20053
20397
|
async function runCutListCli(argv = process.argv.slice(2)) {
|
|
20054
20398
|
const scriptPath = argv[0];
|
|
20055
|
-
if (!scriptPath)
|
|
20399
|
+
if (!scriptPath) usage14();
|
|
20056
20400
|
const source = await readFile2(resolve24(scriptPath), "utf-8");
|
|
20057
20401
|
const { allFiles, fileName } = collectProjectFiles(scriptPath);
|
|
20058
20402
|
await init();
|
|
@@ -20085,7 +20429,7 @@ function hasFlag(argv, name) {
|
|
|
20085
20429
|
const prefix = `${name}=`;
|
|
20086
20430
|
return argv.some((arg) => arg === name || arg.startsWith(prefix));
|
|
20087
20431
|
}
|
|
20088
|
-
function
|
|
20432
|
+
function usage15() {
|
|
20089
20433
|
console.error(
|
|
20090
20434
|
"Usage: forgecad export cutting-layout <script.forge.js> [output.pdf|output.dxf]\n [--format pdf|dxf] [--sheet-width <mm>] [--sheet-height <mm>] [--kerf <mm>]"
|
|
20091
20435
|
);
|
|
@@ -20149,7 +20493,7 @@ function smartDefaults(entries) {
|
|
|
20149
20493
|
}
|
|
20150
20494
|
async function runCuttingLayoutCli(argv = process.argv.slice(2)) {
|
|
20151
20495
|
const scriptPath = argv[0];
|
|
20152
|
-
if (!scriptPath)
|
|
20496
|
+
if (!scriptPath) usage15();
|
|
20153
20497
|
const explicitOutputPath = outputPathArg(argv);
|
|
20154
20498
|
const formatArg = argValue(argv, "--format");
|
|
20155
20499
|
if (hasFlag(argv, "--format") && formatArg == null) {
|
|
@@ -20212,7 +20556,7 @@ function argValue2(argv, name) {
|
|
|
20212
20556
|
if (idx === -1) return void 0;
|
|
20213
20557
|
return argv[idx + 1];
|
|
20214
20558
|
}
|
|
20215
|
-
function
|
|
20559
|
+
function usage16() {
|
|
20216
20560
|
console.error(
|
|
20217
20561
|
"Usage: forgecad export report <model.forge.js|asset.stl|asset.obj|asset.3mf|asset.step|asset.stp> [output.pdf] [--dim-angle-tol <deg>]"
|
|
20218
20562
|
);
|
|
@@ -20220,7 +20564,7 @@ function usage15() {
|
|
|
20220
20564
|
}
|
|
20221
20565
|
async function runReportCli(argv = process.argv.slice(2)) {
|
|
20222
20566
|
const scriptPath = argv[0];
|
|
20223
|
-
if (!scriptPath)
|
|
20567
|
+
if (!scriptPath) usage16();
|
|
20224
20568
|
const defaultOut = replaceCliInputExtension(scriptPath, ".report.pdf");
|
|
20225
20569
|
const outputPath = argv[1] && !argv[1].startsWith("--") ? argv[1] : defaultOut;
|
|
20226
20570
|
const toleranceArg = argValue2(argv, "--dim-angle-tol");
|
|
@@ -20284,16 +20628,16 @@ function mmToM(valueMm) {
|
|
|
20284
20628
|
function degToRad(valueDeg) {
|
|
20285
20629
|
return valueDeg * Math.PI / 180;
|
|
20286
20630
|
}
|
|
20287
|
-
function
|
|
20631
|
+
function formatNumber2(value, digits = 6) {
|
|
20288
20632
|
if (!Number.isFinite(value)) return "0";
|
|
20289
20633
|
const normalized = Math.abs(value) < 1e-12 ? 0 : value;
|
|
20290
20634
|
return normalized.toFixed(digits).replace(/\.?0+$/, "");
|
|
20291
20635
|
}
|
|
20292
20636
|
function formatPose(parts) {
|
|
20293
|
-
return [...parts.xyzM.map((value) =>
|
|
20637
|
+
return [...parts.xyzM.map((value) => formatNumber2(value, 6)), ...parts.rpyRad.map((value) => formatNumber2(value, 6))].join(" ");
|
|
20294
20638
|
}
|
|
20295
20639
|
function axisToText(axis) {
|
|
20296
|
-
return axis.map((value) =>
|
|
20640
|
+
return axis.map((value) => formatNumber2(value, 6)).join(" ");
|
|
20297
20641
|
}
|
|
20298
20642
|
function transformToPose(transform) {
|
|
20299
20643
|
const m = transform.toArray();
|
|
@@ -20439,15 +20783,15 @@ function inertiaFromBounds(geometry, massKg) {
|
|
|
20439
20783
|
}
|
|
20440
20784
|
function jointTypeLimitUnits(joint2, value) {
|
|
20441
20785
|
if (value === void 0) return null;
|
|
20442
|
-
if (joint2.type === "revolute") return
|
|
20443
|
-
if (joint2.type === "prismatic") return
|
|
20786
|
+
if (joint2.type === "revolute") return formatNumber2(degToRad(value), 6);
|
|
20787
|
+
if (joint2.type === "prismatic") return formatNumber2(mmToM(value), 6);
|
|
20444
20788
|
return null;
|
|
20445
20789
|
}
|
|
20446
20790
|
function jointVelocityUnits(joint2, value) {
|
|
20447
20791
|
if (value === void 0) return null;
|
|
20448
|
-
if (joint2.type === "revolute") return
|
|
20449
|
-
if (joint2.type === "prismatic") return
|
|
20450
|
-
return
|
|
20792
|
+
if (joint2.type === "revolute") return formatNumber2(degToRad(value), 6);
|
|
20793
|
+
if (joint2.type === "prismatic") return formatNumber2(mmToM(value), 6);
|
|
20794
|
+
return formatNumber2(value, 6);
|
|
20451
20795
|
}
|
|
20452
20796
|
function sRgbFloat(hex) {
|
|
20453
20797
|
if (!hex || !/^#([0-9a-f]{6})$/i.test(hex)) return null;
|
|
@@ -20476,14 +20820,14 @@ function demoWorldName(world, modelName) {
|
|
|
20476
20820
|
}
|
|
20477
20821
|
function keyboardPluginXml(cmdVelTopic, linearStep, angularStep) {
|
|
20478
20822
|
const bindings = [
|
|
20479
|
-
{ key: 87, twist: `linear: {x: ${
|
|
20480
|
-
{ key: 88, twist: `linear: {x: ${
|
|
20481
|
-
{ key: 65, twist: `linear: {x: 0.0}, angular: {z: ${
|
|
20482
|
-
{ key: 68, twist: `linear: {x: 0.0}, angular: {z: ${
|
|
20483
|
-
{ key: 81, twist: `linear: {x: ${
|
|
20484
|
-
{ key: 69, twist: `linear: {x: ${
|
|
20485
|
-
{ key: 90, twist: `linear: {x: ${
|
|
20486
|
-
{ key: 67, twist: `linear: {x: ${
|
|
20823
|
+
{ key: 87, twist: `linear: {x: ${formatNumber2(linearStep, 3)}}, angular: {z: 0.0}` },
|
|
20824
|
+
{ key: 88, twist: `linear: {x: ${formatNumber2(-linearStep, 3)}}, angular: {z: 0.0}` },
|
|
20825
|
+
{ key: 65, twist: `linear: {x: 0.0}, angular: {z: ${formatNumber2(angularStep, 3)}}` },
|
|
20826
|
+
{ key: 68, twist: `linear: {x: 0.0}, angular: {z: ${formatNumber2(-angularStep, 3)}}` },
|
|
20827
|
+
{ key: 81, twist: `linear: {x: ${formatNumber2(linearStep, 3)}}, angular: {z: ${formatNumber2(angularStep, 3)}}` },
|
|
20828
|
+
{ key: 69, twist: `linear: {x: ${formatNumber2(linearStep, 3)}}, angular: {z: ${formatNumber2(-angularStep, 3)}}` },
|
|
20829
|
+
{ key: 90, twist: `linear: {x: ${formatNumber2(-linearStep, 3)}}, angular: {z: ${formatNumber2(angularStep, 3)}}` },
|
|
20830
|
+
{ key: 67, twist: `linear: {x: ${formatNumber2(-linearStep, 3)}}, angular: {z: ${formatNumber2(-angularStep, 3)}}` },
|
|
20487
20831
|
{ key: 83, twist: "linear: {x: 0.0}, angular: {z: 0.0}" },
|
|
20488
20832
|
{ key: 32, twist: "linear: {x: 0.0}, angular: {z: 0.0}" }
|
|
20489
20833
|
];
|
|
@@ -20643,12 +20987,12 @@ ${keyboardGuiPluginXml()}` : "";
|
|
|
20643
20987
|
function demoWorldXml(worldName, modelName, cmdVelTopic, world) {
|
|
20644
20988
|
const spawnPose = world?.spawnPose ?? [0, 0, 120, 0, 0, 0];
|
|
20645
20989
|
const spawnPoseText = [
|
|
20646
|
-
|
|
20647
|
-
|
|
20648
|
-
|
|
20649
|
-
|
|
20650
|
-
|
|
20651
|
-
|
|
20990
|
+
formatNumber2(mmToM(spawnPose[0]), 6),
|
|
20991
|
+
formatNumber2(mmToM(spawnPose[1]), 6),
|
|
20992
|
+
formatNumber2(mmToM(spawnPose[2]), 6),
|
|
20993
|
+
formatNumber2(degToRad(spawnPose[3]), 6),
|
|
20994
|
+
formatNumber2(degToRad(spawnPose[4]), 6),
|
|
20995
|
+
formatNumber2(degToRad(spawnPose[5]), 6)
|
|
20652
20996
|
].join(" ");
|
|
20653
20997
|
const keyboardEnabled = world?.keyboardTeleop?.enabled ?? true;
|
|
20654
20998
|
const linearStep = world?.keyboardTeleop?.linearStep ?? 0.9;
|
|
@@ -20818,28 +21162,28 @@ function modelXml(spec, modelName, linkNameMap, jointNameMap, geometries, linkWo
|
|
|
20818
21162
|
const color = sRgbFloat(geometry.shapes[0]?.colorHex);
|
|
20819
21163
|
const materialXml = color ? `
|
|
20820
21164
|
<material>
|
|
20821
|
-
<ambient>${
|
|
20822
|
-
<diffuse>${
|
|
21165
|
+
<ambient>${formatNumber2(color[0], 3)} ${formatNumber2(color[1], 3)} ${formatNumber2(color[2], 3)} 1</ambient>
|
|
21166
|
+
<diffuse>${formatNumber2(color[0], 3)} ${formatNumber2(color[1], 3)} ${formatNumber2(color[2], 3)} 1</diffuse>
|
|
20823
21167
|
</material>` : "";
|
|
20824
21168
|
return ` <link name="${escapeXml(sdfLinkName)}">
|
|
20825
21169
|
<pose relative_to="__model__">${formatPose(worldPose)}</pose>
|
|
20826
21170
|
<inertial>
|
|
20827
21171
|
<pose>${formatPose(inertia.pose)}</pose>
|
|
20828
|
-
<mass>${
|
|
21172
|
+
<mass>${formatNumber2(massKg, 6)}</mass>
|
|
20829
21173
|
<inertia>
|
|
20830
|
-
<ixx>${
|
|
20831
|
-
<ixy>${
|
|
20832
|
-
<ixz>${
|
|
20833
|
-
<iyy>${
|
|
20834
|
-
<iyz>${
|
|
20835
|
-
<izz>${
|
|
21174
|
+
<ixx>${formatNumber2(inertia.ixx, 8)}</ixx>
|
|
21175
|
+
<ixy>${formatNumber2(inertia.ixy, 8)}</ixy>
|
|
21176
|
+
<ixz>${formatNumber2(inertia.ixz, 8)}</ixz>
|
|
21177
|
+
<iyy>${formatNumber2(inertia.iyy, 8)}</iyy>
|
|
21178
|
+
<iyz>${formatNumber2(inertia.iyz, 8)}</iyz>
|
|
21179
|
+
<izz>${formatNumber2(inertia.izz, 8)}</izz>
|
|
20836
21180
|
</inertia>
|
|
20837
21181
|
</inertial>
|
|
20838
21182
|
<visual name="${escapeXml(sdfLinkName)}_visual">
|
|
20839
21183
|
<geometry>
|
|
20840
21184
|
<mesh>
|
|
20841
21185
|
<uri>${escapeXml(meshPath)}</uri>
|
|
20842
|
-
<scale>${
|
|
21186
|
+
<scale>${formatNumber2(STL_SCALE_METERS, 6)} ${formatNumber2(STL_SCALE_METERS, 6)} ${formatNumber2(STL_SCALE_METERS, 6)}</scale>
|
|
20843
21187
|
</mesh>
|
|
20844
21188
|
</geometry>${materialXml}
|
|
20845
21189
|
</visual>${(() => {
|
|
@@ -20849,7 +21193,7 @@ function modelXml(spec, modelName, linkNameMap, jointNameMap, geometries, linkWo
|
|
|
20849
21193
|
<geometry>
|
|
20850
21194
|
<mesh>
|
|
20851
21195
|
<uri>${escapeXml(meshPath)}</uri>
|
|
20852
|
-
<scale>${
|
|
21196
|
+
<scale>${formatNumber2(STL_SCALE_METERS, 6)} ${formatNumber2(STL_SCALE_METERS, 6)} ${formatNumber2(STL_SCALE_METERS, 6)}</scale>
|
|
20853
21197
|
</mesh>
|
|
20854
21198
|
</geometry>
|
|
20855
21199
|
</collision>`;
|
|
@@ -20861,7 +21205,7 @@ function modelXml(spec, modelName, linkNameMap, jointNameMap, geometries, linkWo
|
|
|
20861
21205
|
<geometry>
|
|
20862
21206
|
<mesh>
|
|
20863
21207
|
<uri>${escapeXml(collisionMeshPath)}</uri>
|
|
20864
|
-
<scale>${
|
|
21208
|
+
<scale>${formatNumber2(STL_SCALE_METERS, 6)} ${formatNumber2(STL_SCALE_METERS, 6)} ${formatNumber2(STL_SCALE_METERS, 6)}</scale>
|
|
20865
21209
|
</mesh>
|
|
20866
21210
|
</geometry>
|
|
20867
21211
|
</collision>`;
|
|
@@ -20875,9 +21219,9 @@ function modelXml(spec, modelName, linkNameMap, jointNameMap, geometries, linkWo
|
|
|
20875
21219
|
const bCz = mmToM((geometry.bboxMin[2] + geometry.bboxMax[2]) * 0.5);
|
|
20876
21220
|
return `
|
|
20877
21221
|
<collision name="${escapeXml(sdfLinkName)}_collision">
|
|
20878
|
-
<pose>${
|
|
21222
|
+
<pose>${formatNumber2(bCx, 6)} ${formatNumber2(bCy, 6)} ${formatNumber2(bCz, 6)} 0 0 0</pose>
|
|
20879
21223
|
<geometry>
|
|
20880
|
-
<box><size>${
|
|
21224
|
+
<box><size>${formatNumber2(bDx, 6)} ${formatNumber2(bDy, 6)} ${formatNumber2(bDz, 6)}</size></box>
|
|
20881
21225
|
</geometry>
|
|
20882
21226
|
</collision>`;
|
|
20883
21227
|
}
|
|
@@ -20904,8 +21248,8 @@ function modelXml(spec, modelName, linkNameMap, jointNameMap, geometries, linkWo
|
|
|
20904
21248
|
const leaderSdfName = jointNameMap.get(`${primary.joint}_joint`);
|
|
20905
21249
|
mimicXml = `
|
|
20906
21250
|
<mimic joint="${escapeXml(leaderSdfName)}">
|
|
20907
|
-
<multiplier>${
|
|
20908
|
-
<offset>${
|
|
21251
|
+
<multiplier>${formatNumber2(primary.ratio, 6)}</multiplier>
|
|
21252
|
+
<offset>${formatNumber2(coupling.offset, 6)}</offset>
|
|
20909
21253
|
</mimic>`;
|
|
20910
21254
|
if (coupling.terms.length > 1) {
|
|
20911
21255
|
warnings.push(
|
|
@@ -20922,12 +21266,12 @@ function modelXml(spec, modelName, linkNameMap, jointNameMap, geometries, linkWo
|
|
|
20922
21266
|
<limit>${limitLower !== null ? `
|
|
20923
21267
|
<lower>${limitLower}</lower>` : ""}${limitUpper !== null ? `
|
|
20924
21268
|
<upper>${limitUpper}</upper>` : ""}${effort !== void 0 ? `
|
|
20925
|
-
<effort>${
|
|
21269
|
+
<effort>${formatNumber2(effort, 6)}</effort>` : ""}${velocity !== null ? `
|
|
20926
21270
|
<velocity>${velocity}</velocity>` : ""}
|
|
20927
21271
|
</limit>` : ""}${damping !== void 0 || friction !== void 0 ? `
|
|
20928
21272
|
<dynamics>${damping !== void 0 ? `
|
|
20929
|
-
<damping>${
|
|
20930
|
-
<friction>${
|
|
21273
|
+
<damping>${formatNumber2(damping, 6)}</damping>` : ""}${friction !== void 0 ? `
|
|
21274
|
+
<friction>${formatNumber2(friction, 6)}</friction>` : ""}
|
|
20931
21275
|
</dynamics>` : ""}
|
|
20932
21276
|
</axis>` : ""}
|
|
20933
21277
|
</joint>`;
|
|
@@ -20937,17 +21281,17 @@ function modelXml(spec, modelName, linkNameMap, jointNameMap, geometries, linkWo
|
|
|
20937
21281
|
plugins.push(` <plugin filename="gz-sim-diff-drive-system" name="gz::sim::systems::DiffDrive">
|
|
20938
21282
|
${spec.plugins.diffDrive.leftJoints.map((jointName) => `<left_joint>${escapeXml(jointNameMap.get(`${jointName}_joint`))}</left_joint>`).join("\n ")}
|
|
20939
21283
|
${spec.plugins.diffDrive.rightJoints.map((jointName) => `<right_joint>${escapeXml(jointNameMap.get(`${jointName}_joint`))}</right_joint>`).join("\n ")}
|
|
20940
|
-
<wheel_separation>${
|
|
20941
|
-
<wheel_radius>${
|
|
21284
|
+
<wheel_separation>${formatNumber2(mmToM(spec.plugins.diffDrive.wheelSeparationMm), 6)}</wheel_separation>
|
|
21285
|
+
<wheel_radius>${formatNumber2(mmToM(spec.plugins.diffDrive.wheelRadiusMm), 6)}</wheel_radius>
|
|
20942
21286
|
<topic>${escapeXml(cmdVelTopic)}</topic>${spec.plugins.diffDrive.odomTopic ? `
|
|
20943
21287
|
<odom_topic>${escapeXml(spec.plugins.diffDrive.odomTopic)}</odom_topic>` : ""}${spec.plugins.diffDrive.tfTopic ? `
|
|
20944
21288
|
<tf_topic>${escapeXml(spec.plugins.diffDrive.tfTopic)}</tf_topic>` : ""}${spec.plugins.diffDrive.frameId ? `
|
|
20945
21289
|
<frame_id>${escapeXml(spec.plugins.diffDrive.frameId)}</frame_id>` : ""}${spec.plugins.diffDrive.odomFrameId ? `
|
|
20946
21290
|
<odom_frame>${escapeXml(spec.plugins.diffDrive.odomFrameId)}</odom_frame>` : ""}${spec.plugins.diffDrive.maxLinearVelocity !== void 0 ? `
|
|
20947
|
-
<max_linear_velocity>${
|
|
20948
|
-
<max_angular_velocity>${
|
|
20949
|
-
<linear_acceleration>${
|
|
20950
|
-
<angular_acceleration>${
|
|
21291
|
+
<max_linear_velocity>${formatNumber2(spec.plugins.diffDrive.maxLinearVelocity, 6)}</max_linear_velocity>` : ""}${spec.plugins.diffDrive.maxAngularVelocity !== void 0 ? `
|
|
21292
|
+
<max_angular_velocity>${formatNumber2(spec.plugins.diffDrive.maxAngularVelocity, 6)}</max_angular_velocity>` : ""}${spec.plugins.diffDrive.linearAcceleration !== void 0 ? `
|
|
21293
|
+
<linear_acceleration>${formatNumber2(spec.plugins.diffDrive.linearAcceleration, 6)}</linear_acceleration>` : ""}${spec.plugins.diffDrive.angularAcceleration !== void 0 ? `
|
|
21294
|
+
<angular_acceleration>${formatNumber2(spec.plugins.diffDrive.angularAcceleration, 6)}</angular_acceleration>` : ""}
|
|
20951
21295
|
</plugin>`);
|
|
20952
21296
|
}
|
|
20953
21297
|
const jointState = spec.plugins.jointStatePublisher;
|
|
@@ -20957,7 +21301,7 @@ function modelXml(spec, modelName, linkNameMap, jointNameMap, geometries, linkWo
|
|
|
20957
21301
|
(jointName) => `
|
|
20958
21302
|
<joint_name>${escapeXml(jointNameMap.get(`${jointName}_joint`))}</joint_name>`
|
|
20959
21303
|
).join("")}${jointState?.updateRate !== void 0 ? `
|
|
20960
|
-
<update_rate>${
|
|
21304
|
+
<update_rate>${formatNumber2(jointState.updateRate, 6)}</update_rate>` : ""}
|
|
20961
21305
|
</plugin>`);
|
|
20962
21306
|
}
|
|
20963
21307
|
const rootNames = spec.assembly.parts.filter((part) => !spec.assembly.joints.some((joint2) => joint2.child === part.name)).map((part) => linkNameMap.get(part.name));
|
|
@@ -21149,6 +21493,129 @@ async function runSdfCli(argv = process.argv.slice(2)) {
|
|
|
21149
21493
|
}
|
|
21150
21494
|
}
|
|
21151
21495
|
|
|
21496
|
+
// cli/forge-show.ts
|
|
21497
|
+
var FORWARDED_VALUE_OPTIONS = /* @__PURE__ */ new Set([
|
|
21498
|
+
"--camera",
|
|
21499
|
+
"--camera-json",
|
|
21500
|
+
"--view",
|
|
21501
|
+
"--scene",
|
|
21502
|
+
"--background",
|
|
21503
|
+
"--render-style",
|
|
21504
|
+
"--edges",
|
|
21505
|
+
"--size",
|
|
21506
|
+
"--port",
|
|
21507
|
+
"--chrome-path",
|
|
21508
|
+
"--backend",
|
|
21509
|
+
"--param",
|
|
21510
|
+
"-p",
|
|
21511
|
+
"--render-mode",
|
|
21512
|
+
"--scan-granularity"
|
|
21513
|
+
]);
|
|
21514
|
+
var FORWARDED_FLAG_OPTIONS = /* @__PURE__ */ new Set(["--fresh-server"]);
|
|
21515
|
+
var CAMERA_SOURCE_OPTIONS = /* @__PURE__ */ new Set(["--camera", "--camera-json", "--view", "--scene"]);
|
|
21516
|
+
function usage17() {
|
|
21517
|
+
return [
|
|
21518
|
+
"Usage: forgecad show <model.forge.js|asset.stl|asset.obj|asset.3mf|asset.step|asset.stp> [target] [output.png] [--from front|back|side|right|top|iso|az:el|az:el:dist] [--out output.png] [--param Key=Value] [--backend manifold|occt|truck] [render options]"
|
|
21519
|
+
].join("\n");
|
|
21520
|
+
}
|
|
21521
|
+
function isImageOutput(value) {
|
|
21522
|
+
return /\.(png|jpg|jpeg|webp)$/i.test(value);
|
|
21523
|
+
}
|
|
21524
|
+
function readValue6(argv, index, flag) {
|
|
21525
|
+
const value = argv[index + 1];
|
|
21526
|
+
if (!value || value.startsWith("--")) throw new Error(`${flag} requires a value.`);
|
|
21527
|
+
return value;
|
|
21528
|
+
}
|
|
21529
|
+
function parseShowOptions(argv) {
|
|
21530
|
+
if (argv.length === 0 || argv.includes("-h") || argv.includes("--help")) {
|
|
21531
|
+
console.log(usage17());
|
|
21532
|
+
process.exit(0);
|
|
21533
|
+
}
|
|
21534
|
+
const consumed = /* @__PURE__ */ new Set();
|
|
21535
|
+
const renderArgs = [];
|
|
21536
|
+
let output;
|
|
21537
|
+
let from;
|
|
21538
|
+
let hasRenderCameraSource = false;
|
|
21539
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
21540
|
+
const arg = argv[i];
|
|
21541
|
+
if (arg === "--from") {
|
|
21542
|
+
from = readValue6(argv, i, arg);
|
|
21543
|
+
consumed.add(i);
|
|
21544
|
+
consumed.add(i + 1);
|
|
21545
|
+
i += 1;
|
|
21546
|
+
continue;
|
|
21547
|
+
}
|
|
21548
|
+
if (arg === "--out" || arg === "--output") {
|
|
21549
|
+
output = readValue6(argv, i, arg);
|
|
21550
|
+
consumed.add(i);
|
|
21551
|
+
consumed.add(i + 1);
|
|
21552
|
+
i += 1;
|
|
21553
|
+
continue;
|
|
21554
|
+
}
|
|
21555
|
+
if (FORWARDED_VALUE_OPTIONS.has(arg)) {
|
|
21556
|
+
const value = readValue6(argv, i, arg);
|
|
21557
|
+
renderArgs.push(arg, value);
|
|
21558
|
+
if (CAMERA_SOURCE_OPTIONS.has(arg)) hasRenderCameraSource = true;
|
|
21559
|
+
consumed.add(i);
|
|
21560
|
+
consumed.add(i + 1);
|
|
21561
|
+
i += 1;
|
|
21562
|
+
continue;
|
|
21563
|
+
}
|
|
21564
|
+
if (FORWARDED_FLAG_OPTIONS.has(arg)) {
|
|
21565
|
+
renderArgs.push(arg);
|
|
21566
|
+
consumed.add(i);
|
|
21567
|
+
continue;
|
|
21568
|
+
}
|
|
21569
|
+
if (arg.startsWith("--")) throw new Error(`Unknown option: ${arg}`);
|
|
21570
|
+
}
|
|
21571
|
+
if (from && hasRenderCameraSource) throw new Error("Use either --from or an explicit render camera option, not both.");
|
|
21572
|
+
const positionals = argv.filter((_, index) => !consumed.has(index));
|
|
21573
|
+
const scriptPath = positionals[0];
|
|
21574
|
+
if (!scriptPath) throw new Error("Missing input path.");
|
|
21575
|
+
let target;
|
|
21576
|
+
if (positionals.length === 2) {
|
|
21577
|
+
if (!output && isImageOutput(positionals[1])) output = positionals[1];
|
|
21578
|
+
else target = positionals[1];
|
|
21579
|
+
} else if (positionals.length === 3) {
|
|
21580
|
+
target = positionals[1];
|
|
21581
|
+
if (output) throw new Error("Pass output either positionally or with --out, not both.");
|
|
21582
|
+
output = positionals[2];
|
|
21583
|
+
} else if (positionals.length > 3) {
|
|
21584
|
+
throw new Error(`Unexpected argument: ${positionals[3]}`);
|
|
21585
|
+
}
|
|
21586
|
+
return { scriptPath, target, output, from, renderArgs, consumed };
|
|
21587
|
+
}
|
|
21588
|
+
function renderFocusForTargetNames(names) {
|
|
21589
|
+
return names.join(",");
|
|
21590
|
+
}
|
|
21591
|
+
async function runShowCli(argv = process.argv.slice(2)) {
|
|
21592
|
+
let options;
|
|
21593
|
+
try {
|
|
21594
|
+
options = parseShowOptions(argv);
|
|
21595
|
+
} catch (error) {
|
|
21596
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
21597
|
+
console.error(usage17());
|
|
21598
|
+
process.exit(1);
|
|
21599
|
+
}
|
|
21600
|
+
const renderArgs = [options.scriptPath];
|
|
21601
|
+
if (options.output) renderArgs.push(options.output);
|
|
21602
|
+
if (options.from) renderArgs.push("--camera", options.from);
|
|
21603
|
+
renderArgs.push(...options.renderArgs);
|
|
21604
|
+
if (options.target) {
|
|
21605
|
+
const { overrides } = parseParamFlags(argv);
|
|
21606
|
+
const { backend } = parseBackendArg(argv);
|
|
21607
|
+
const result = await runModelForInspect(options.scriptPath, backend, void 0, overrides);
|
|
21608
|
+
if (result.error) {
|
|
21609
|
+
console.error("ERROR:", result.error);
|
|
21610
|
+
process.exit(1);
|
|
21611
|
+
}
|
|
21612
|
+
const targets = resolveSceneTargets(buildSceneTargetEntries(result.objects), options.target);
|
|
21613
|
+
renderArgs.push("--focus", renderFocusForTargetNames(targets.map((target) => target.name)));
|
|
21614
|
+
console.log(`Target: ${targets.map(formatSceneTargetPath).join(", ")}`);
|
|
21615
|
+
}
|
|
21616
|
+
await runRenderCli(renderArgs);
|
|
21617
|
+
}
|
|
21618
|
+
|
|
21152
21619
|
// cli/forge-sketch-pdf.ts
|
|
21153
21620
|
import { readFile as readFile4, writeFile as writeFile7 } from "fs/promises";
|
|
21154
21621
|
import { basename as basename12, resolve as resolve28 } from "path";
|
|
@@ -21708,7 +22175,7 @@ function generateSketchPdf(meta, options) {
|
|
|
21708
22175
|
}
|
|
21709
22176
|
|
|
21710
22177
|
// cli/forge-sketch-pdf.ts
|
|
21711
|
-
function
|
|
22178
|
+
function usage18() {
|
|
21712
22179
|
console.error("Usage: forgecad export sketch-pdf <script.forge.js> [output.pdf]");
|
|
21713
22180
|
process.exit(1);
|
|
21714
22181
|
}
|
|
@@ -21717,7 +22184,7 @@ function defaultPdfOutput(scriptPath) {
|
|
|
21717
22184
|
}
|
|
21718
22185
|
async function runSketchPdfCli(argv = process.argv.slice(2)) {
|
|
21719
22186
|
const scriptPath = argv[0];
|
|
21720
|
-
if (!scriptPath)
|
|
22187
|
+
if (!scriptPath) usage18();
|
|
21721
22188
|
const outputPath = argv[1] || defaultPdfOutput(scriptPath);
|
|
21722
22189
|
if (resolve28(outputPath) === resolve28(scriptPath)) {
|
|
21723
22190
|
console.error(`ERROR: output path would overwrite the input script. Specify an explicit output path.`);
|
|
@@ -22157,7 +22624,7 @@ function getServerUrl() {
|
|
|
22157
22624
|
}
|
|
22158
22625
|
function cliAuthRequiredMessage() {
|
|
22159
22626
|
return [
|
|
22160
|
-
"ForgeCAD CLI
|
|
22627
|
+
"This ForgeCAD CLI command requires a ForgeCAD account.",
|
|
22161
22628
|
"",
|
|
22162
22629
|
" New account: forgecad signup",
|
|
22163
22630
|
" Interactive sign-in: forgecad login",
|
|
@@ -23545,7 +24012,7 @@ data: ${JSON.stringify(data)}
|
|
|
23545
24012
|
}
|
|
23546
24013
|
|
|
23547
24014
|
// cli/forge-studio.ts
|
|
23548
|
-
function
|
|
24015
|
+
function usage19() {
|
|
23549
24016
|
console.error(`ForgeCAD Studio
|
|
23550
24017
|
|
|
23551
24018
|
Usage:
|
|
@@ -23575,7 +24042,7 @@ function parseStudioArgs(argv) {
|
|
|
23575
24042
|
if (argv.length === 0) {
|
|
23576
24043
|
throw new Error("Missing project path. Use `forgecad studio <project-path> [project-path ...]`.");
|
|
23577
24044
|
}
|
|
23578
|
-
if (argv.includes("-h") || argv.includes("--help"))
|
|
24045
|
+
if (argv.includes("-h") || argv.includes("--help")) usage19();
|
|
23579
24046
|
const options = { open: false, strictPort: false, projectPaths: [] };
|
|
23580
24047
|
for (let i = 0; i < argv.length; i += 1) {
|
|
23581
24048
|
const arg = argv[i];
|
|
@@ -23650,7 +24117,7 @@ async function runStudioCli(argv = process.argv.slice(2)) {
|
|
|
23650
24117
|
// cli/forge-svg.ts
|
|
23651
24118
|
import { readFile as readFile5, writeFile as writeFile8 } from "fs/promises";
|
|
23652
24119
|
import { basename as basename13, resolve as resolve31 } from "path";
|
|
23653
|
-
function
|
|
24120
|
+
function usage20() {
|
|
23654
24121
|
console.error("Usage: forgecad export svg <script.forge.js> [output.svg]");
|
|
23655
24122
|
process.exit(1);
|
|
23656
24123
|
}
|
|
@@ -23659,7 +24126,7 @@ function defaultSvgOutput(scriptPath) {
|
|
|
23659
24126
|
}
|
|
23660
24127
|
async function runSvgCli(argv = process.argv.slice(2)) {
|
|
23661
24128
|
const scriptPath = argv[0];
|
|
23662
|
-
if (!scriptPath)
|
|
24129
|
+
if (!scriptPath) usage20();
|
|
23663
24130
|
const outputPath = argv[1] || defaultSvgOutput(scriptPath);
|
|
23664
24131
|
if (resolve31(outputPath) === resolve31(scriptPath)) {
|
|
23665
24132
|
console.error(`ERROR: output path would overwrite the input script. Specify an explicit output path.`);
|
|
@@ -23727,7 +24194,7 @@ function mmToM2(valueMm) {
|
|
|
23727
24194
|
function degToRad2(valueDeg) {
|
|
23728
24195
|
return valueDeg * Math.PI / 180;
|
|
23729
24196
|
}
|
|
23730
|
-
function
|
|
24197
|
+
function formatNumber3(value, digits = 6) {
|
|
23731
24198
|
if (!Number.isFinite(value)) return "0";
|
|
23732
24199
|
const normalized = Math.abs(value) < 1e-12 ? 0 : value;
|
|
23733
24200
|
return normalized.toFixed(digits).replace(/\.?0+$/, "");
|
|
@@ -23850,7 +24317,7 @@ function transformToOrigin(transform) {
|
|
|
23850
24317
|
yaw = Math.atan2(r10, r00);
|
|
23851
24318
|
}
|
|
23852
24319
|
const x = mmToM2(m[12]), y = mmToM2(m[13]), z = mmToM2(m[14]);
|
|
23853
|
-
return `xyz="${
|
|
24320
|
+
return `xyz="${formatNumber3(x)} ${formatNumber3(y)} ${formatNumber3(z)}" rpy="${formatNumber3(roll)} ${formatNumber3(pitch)} ${formatNumber3(yaw)}"`;
|
|
23854
24321
|
}
|
|
23855
24322
|
function sRgbFloat2(hex) {
|
|
23856
24323
|
if (!hex || !/^#([0-9a-f]{6})$/i.test(hex)) return null;
|
|
@@ -23911,7 +24378,7 @@ function urdfXml(spec, modelName, linkNameMap, jointNameMap, geometries, _linkWo
|
|
|
23911
24378
|
const color = sRgbFloat2(geometry.shapes[0]?.colorHex);
|
|
23912
24379
|
const materialXml = color ? `
|
|
23913
24380
|
<material name="${escapeXml2(urdfLinkName)}_material">
|
|
23914
|
-
<color rgba="${
|
|
24381
|
+
<color rgba="${formatNumber3(color[0], 3)} ${formatNumber3(color[1], 3)} ${formatNumber3(color[2], 3)} 1"/>
|
|
23915
24382
|
</material>` : "";
|
|
23916
24383
|
let collisionXml = "";
|
|
23917
24384
|
if (collisionMode === "visual") {
|
|
@@ -23940,17 +24407,17 @@ function urdfXml(spec, modelName, linkNameMap, jointNameMap, geometries, _linkWo
|
|
|
23940
24407
|
const bCz = mmToM2((geometry.bboxMin[2] + geometry.bboxMax[2]) * 0.5);
|
|
23941
24408
|
collisionXml = `
|
|
23942
24409
|
<collision>
|
|
23943
|
-
<origin xyz="${
|
|
24410
|
+
<origin xyz="${formatNumber3(bCx)} ${formatNumber3(bCy)} ${formatNumber3(bCz)}" rpy="0 0 0"/>
|
|
23944
24411
|
<geometry>
|
|
23945
|
-
<box size="${
|
|
24412
|
+
<box size="${formatNumber3(bDx)} ${formatNumber3(bDy)} ${formatNumber3(bDz)}"/>
|
|
23946
24413
|
</geometry>
|
|
23947
24414
|
</collision>`;
|
|
23948
24415
|
}
|
|
23949
24416
|
return ` <link name="${escapeXml2(urdfLinkName)}">
|
|
23950
24417
|
<inertial>
|
|
23951
|
-
<origin xyz="${
|
|
23952
|
-
<mass value="${
|
|
23953
|
-
<inertia ixx="${
|
|
24418
|
+
<origin xyz="${formatNumber3(comX)} ${formatNumber3(comY)} ${formatNumber3(comZ)}" rpy="0 0 0"/>
|
|
24419
|
+
<mass value="${formatNumber3(massKg, 6)}"/>
|
|
24420
|
+
<inertia ixx="${formatNumber3(ixx, 8)}" ixy="${formatNumber3(ixy, 8)}" ixz="${formatNumber3(ixz, 8)}" iyy="${formatNumber3(iyy, 8)}" iyz="${formatNumber3(iyz, 8)}" izz="${formatNumber3(izz, 8)}"/>
|
|
23954
24421
|
</inertial>
|
|
23955
24422
|
<visual>
|
|
23956
24423
|
<geometry>
|
|
@@ -23967,7 +24434,7 @@ function urdfXml(spec, modelName, linkNameMap, jointNameMap, geometries, _linkWo
|
|
|
23967
24434
|
const jType = urdfJointHasContinuous(joint2) ? "continuous" : urdfJointType(joint2.type);
|
|
23968
24435
|
const originAttr = transformToOrigin(joint2.frame);
|
|
23969
24436
|
const axisXml = joint2.type !== "fixed" ? `
|
|
23970
|
-
<axis xyz="${joint2.axis.map((v) =>
|
|
24437
|
+
<axis xyz="${joint2.axis.map((v) => formatNumber3(v)).join(" ")}"/>` : "";
|
|
23971
24438
|
let limitXml = "";
|
|
23972
24439
|
if (joint2.type !== "fixed" && jType !== "continuous") {
|
|
23973
24440
|
const lower2 = joint2.min !== void 0 ? joint2.type === "revolute" ? degToRad2(joint2.min) : mmToM2(joint2.min) : void 0;
|
|
@@ -23976,20 +24443,20 @@ function urdfXml(spec, modelName, linkNameMap, jointNameMap, geometries, _linkWo
|
|
|
23976
24443
|
const velocity = sourceOverrides?.velocity ?? joint2.velocity;
|
|
23977
24444
|
const vel = velocity !== void 0 ? joint2.type === "revolute" ? degToRad2(velocity) : mmToM2(velocity) : 10;
|
|
23978
24445
|
limitXml = `
|
|
23979
|
-
<limit${lower2 !== void 0 ? ` lower="${
|
|
24446
|
+
<limit${lower2 !== void 0 ? ` lower="${formatNumber3(lower2)}"` : ""}${upper !== void 0 ? ` upper="${formatNumber3(upper)}"` : ""} effort="${formatNumber3(effort)}" velocity="${formatNumber3(vel)}"/>`;
|
|
23980
24447
|
} else if (jType === "continuous") {
|
|
23981
24448
|
const effort = sourceOverrides?.effort ?? joint2.effort ?? 100;
|
|
23982
24449
|
const velocity = sourceOverrides?.velocity ?? joint2.velocity;
|
|
23983
24450
|
const vel = velocity !== void 0 ? degToRad2(velocity) : 10;
|
|
23984
24451
|
limitXml = `
|
|
23985
|
-
<limit effort="${
|
|
24452
|
+
<limit effort="${formatNumber3(effort)}" velocity="${formatNumber3(vel)}"/>`;
|
|
23986
24453
|
}
|
|
23987
24454
|
let dynamicsXml = "";
|
|
23988
24455
|
const damping = sourceOverrides?.damping ?? joint2.damping;
|
|
23989
24456
|
const friction = sourceOverrides?.friction ?? joint2.friction;
|
|
23990
24457
|
if (damping !== void 0 || friction !== void 0) {
|
|
23991
24458
|
dynamicsXml = `
|
|
23992
|
-
<dynamics${damping !== void 0 ? ` damping="${
|
|
24459
|
+
<dynamics${damping !== void 0 ? ` damping="${formatNumber3(damping)}"` : ""}${friction !== void 0 ? ` friction="${formatNumber3(friction)}"` : ""}/>`;
|
|
23993
24460
|
}
|
|
23994
24461
|
let mimicXml = "";
|
|
23995
24462
|
const coupling = couplingByJoint.get(joint2.name);
|
|
@@ -23997,7 +24464,7 @@ function urdfXml(spec, modelName, linkNameMap, jointNameMap, geometries, _linkWo
|
|
|
23997
24464
|
const primary = coupling.terms.reduce((a, b) => Math.abs(a.ratio) >= Math.abs(b.ratio) ? a : b);
|
|
23998
24465
|
const leaderUrdfName = jointNameMap.get(`${primary.joint}_joint`);
|
|
23999
24466
|
mimicXml = `
|
|
24000
|
-
<mimic joint="${escapeXml2(leaderUrdfName)}" multiplier="${
|
|
24467
|
+
<mimic joint="${escapeXml2(leaderUrdfName)}" multiplier="${formatNumber3(primary.ratio)}" offset="${formatNumber3(coupling.offset)}"/>`;
|
|
24001
24468
|
if (coupling.terms.length > 1) {
|
|
24002
24469
|
warnings.push(
|
|
24003
24470
|
`Joint "${joint2.name}" coupling has ${coupling.terms.length} terms but URDF mimic only supports 1. Using primary term (ratio=${primary.ratio} from "${primary.joint}").`
|
|
@@ -25932,13 +26399,13 @@ function findCollisions(entries) {
|
|
|
25932
26399
|
}
|
|
25933
26400
|
return collisions;
|
|
25934
26401
|
}
|
|
25935
|
-
function
|
|
26402
|
+
function usage21() {
|
|
25936
26403
|
console.error("Usage: forgecad check params <script.forge.js> [--samples N]");
|
|
25937
26404
|
process.exit(1);
|
|
25938
26405
|
}
|
|
25939
26406
|
async function runParamCheckCli(argv = process.argv.slice(2)) {
|
|
25940
26407
|
const scriptPath = argv[0];
|
|
25941
|
-
if (!scriptPath)
|
|
26408
|
+
if (!scriptPath) usage21();
|
|
25942
26409
|
const samplesArg = argv.indexOf("--samples");
|
|
25943
26410
|
const numSamples = samplesArg >= 0 ? parseInt(argv[samplesArg + 1], 10) : 8;
|
|
25944
26411
|
const code = readFileSync21(resolve35(scriptPath), "utf-8");
|
|
@@ -26618,7 +27085,7 @@ function buildPrintCheckReport(objects, verifications, options) {
|
|
|
26618
27085
|
}
|
|
26619
27086
|
|
|
26620
27087
|
// cli/print-check.ts
|
|
26621
|
-
function
|
|
27088
|
+
function usage22() {
|
|
26622
27089
|
console.error(
|
|
26623
27090
|
"Usage: forgecad check print <model.forge.js|asset.stl|asset.obj|asset.3mf|asset.step|asset.stp> [--json] [--output report.json] [--profile fdm-pla-0.4mm] [--param Key=Value]"
|
|
26624
27091
|
);
|
|
@@ -26745,7 +27212,7 @@ function parseArgs10(argv) {
|
|
|
26745
27212
|
}
|
|
26746
27213
|
const positional = argv.filter((arg, index) => !consumed.has(index) && !arg.startsWith("-"));
|
|
26747
27214
|
const scriptPath = positional[0];
|
|
26748
|
-
if (!scriptPath)
|
|
27215
|
+
if (!scriptPath) usage22();
|
|
26749
27216
|
return {
|
|
26750
27217
|
scriptPath,
|
|
26751
27218
|
json,
|
|
@@ -27651,25 +28118,7 @@ async function writeSolverDebugIndex(root, scriptPath, bundles) {
|
|
|
27651
28118
|
}
|
|
27652
28119
|
|
|
27653
28120
|
// cli/test-run.ts
|
|
27654
|
-
var DEFAULT_EXACT_SPATIAL_OBJECT_LIMIT = 250;
|
|
27655
|
-
var SPATIAL_BBOX_PADDING = 0.1;
|
|
27656
|
-
var MAX_SPATIAL_COLLISION_LINES = 50;
|
|
27657
28121
|
var MAX_COMPACT_OBJECT_NAMES = 24;
|
|
27658
|
-
function parseSpatialMode(argv, defaultMode) {
|
|
27659
|
-
const consumed = /* @__PURE__ */ new Set();
|
|
27660
|
-
const idx = argv.indexOf("--spatial");
|
|
27661
|
-
if (idx === -1) return { mode: defaultMode, consumed, explicit: false };
|
|
27662
|
-
consumed.add(idx);
|
|
27663
|
-
const raw = argv[idx + 1];
|
|
27664
|
-
if (!raw || raw.startsWith("-")) {
|
|
27665
|
-
console.error("Missing value for --spatial. Expected bounded, exact, or off.");
|
|
27666
|
-
process.exit(1);
|
|
27667
|
-
}
|
|
27668
|
-
consumed.add(idx + 1);
|
|
27669
|
-
if (raw === "bounded" || raw === "exact" || raw === "off") return { mode: raw, consumed, explicit: true };
|
|
27670
|
-
console.error(`Invalid --spatial value: ${raw}. Expected bounded, exact, or off.`);
|
|
27671
|
-
process.exit(1);
|
|
27672
|
-
}
|
|
27673
28122
|
function buildJourneyInspection(journeys) {
|
|
27674
28123
|
return {
|
|
27675
28124
|
journeys: Object.entries(journeys ?? {}).map(([id, journey]) => ({
|
|
@@ -27807,137 +28256,6 @@ function formatFeatureSummary(counts) {
|
|
|
27807
28256
|
collect("imports", imports);
|
|
27808
28257
|
return groups.join(" | ");
|
|
27809
28258
|
}
|
|
27810
|
-
function analyzeSpatial(entries, mode) {
|
|
27811
|
-
const lines = [];
|
|
27812
|
-
const _axisLabel = ["X", "Y", "Z"];
|
|
27813
|
-
const dirLabels = {
|
|
27814
|
-
0: ["LEFT of", "RIGHT of"],
|
|
27815
|
-
1: ["IN FRONT of", "BEHIND"],
|
|
27816
|
-
2: ["BELOW", "ABOVE"]
|
|
27817
|
-
};
|
|
27818
|
-
const allMin = [Infinity, Infinity, Infinity];
|
|
27819
|
-
const allMax = [-Infinity, -Infinity, -Infinity];
|
|
27820
|
-
for (const s of entries) {
|
|
27821
|
-
for (let ax = 0; ax < 3; ax++) {
|
|
27822
|
-
allMin[ax] = Math.min(allMin[ax], s.min[ax]);
|
|
27823
|
-
allMax[ax] = Math.max(allMax[ax], s.max[ax]);
|
|
27824
|
-
}
|
|
27825
|
-
}
|
|
27826
|
-
const sceneSize = Math.max(...allMax.map((v, i) => v - allMin[i]));
|
|
27827
|
-
const proximityThreshold = sceneSize * 0.15;
|
|
27828
|
-
const exactCollisionChecksEnabled = mode === "exact" || entries.length <= DEFAULT_EXACT_SPATIAL_OBJECT_LIMIT;
|
|
27829
|
-
const collisionReport = analyzeCollisionIntersections(entries, {
|
|
27830
|
-
bboxPadding: SPATIAL_BBOX_PADDING,
|
|
27831
|
-
skipIntraGroup: true,
|
|
27832
|
-
skipMockPairs: true,
|
|
27833
|
-
includeBBoxCandidates: false,
|
|
27834
|
-
...exactCollisionChecksEnabled ? {} : { maxCandidatePairs: 0 }
|
|
27835
|
-
});
|
|
27836
|
-
if (!exactCollisionChecksEnabled && collisionReport.candidatePairCount > 0) {
|
|
27837
|
-
lines.push(
|
|
27838
|
-
` Exact collision checks skipped for ${collisionReport.candidatePairCount} bbox-overlapping pair(s) in this ${entries.length}-object scene. Re-run with --spatial exact for exhaustive pairwise intersections.`
|
|
27839
|
-
);
|
|
27840
|
-
} else if (collisionReport.candidatePairCount > 0 && exactCollisionChecksEnabled) {
|
|
27841
|
-
lines.push(
|
|
27842
|
-
` Exact collision checks: ${collisionReport.testedPairCount} bbox-overlapping pair(s) tested in ${collisionReport.exactCheckMs.toFixed(0)}ms.`
|
|
27843
|
-
);
|
|
27844
|
-
}
|
|
27845
|
-
for (const collision of collisionReport.collisions.slice(0, MAX_SPATIAL_COLLISION_LINES)) {
|
|
27846
|
-
lines.push(` \u26A0 COLLISION: ${collision.sourceName} \u2229 ${collision.targetName} (shared vol: ${collision.overlapVolume.toFixed(1)}mm\xB3)`);
|
|
27847
|
-
}
|
|
27848
|
-
if (collisionReport.collisionCount > MAX_SPATIAL_COLLISION_LINES) {
|
|
27849
|
-
lines.push(
|
|
27850
|
-
` ... ${collisionReport.collisionCount - MAX_SPATIAL_COLLISION_LINES} more collision(s) omitted; use --focus/--hide or inspect fit interference to narrow the scene.`
|
|
27851
|
-
);
|
|
27852
|
-
}
|
|
27853
|
-
for (const warning of collisionReport.warnings) {
|
|
27854
|
-
if (warning.includes("maxCandidatePairs=0")) continue;
|
|
27855
|
-
lines.push(` Warning: ${warning}`);
|
|
27856
|
-
}
|
|
27857
|
-
for (let i = 0; i < entries.length; i++) {
|
|
27858
|
-
const a = entries[i];
|
|
27859
|
-
const nearest = Array.from({ length: 6 }, () => ({ idx: -1, gap: Infinity }));
|
|
27860
|
-
for (let j = 0; j < entries.length; j++) {
|
|
27861
|
-
if (i === j) continue;
|
|
27862
|
-
const b = entries[j];
|
|
27863
|
-
for (let ax = 0; ax < 3; ax++) {
|
|
27864
|
-
if (a.max[ax] < b.min[ax]) {
|
|
27865
|
-
const gap = b.min[ax] - a.max[ax];
|
|
27866
|
-
const d = ax * 2;
|
|
27867
|
-
if (gap < nearest[d].gap) nearest[d] = { idx: j, gap };
|
|
27868
|
-
} else if (b.max[ax] < a.min[ax]) {
|
|
27869
|
-
const gap = a.min[ax] - b.max[ax];
|
|
27870
|
-
const d = ax * 2 + 1;
|
|
27871
|
-
if (gap < nearest[d].gap) nearest[d] = { idx: j, gap };
|
|
27872
|
-
}
|
|
27873
|
-
}
|
|
27874
|
-
}
|
|
27875
|
-
for (let d = 0; d < 6; d++) {
|
|
27876
|
-
const n = nearest[d];
|
|
27877
|
-
if (n.idx === -1 || n.gap > proximityThreshold) continue;
|
|
27878
|
-
const b = entries[n.idx];
|
|
27879
|
-
const ax = Math.floor(d / 2);
|
|
27880
|
-
const isPositive = d % 2 === 0;
|
|
27881
|
-
const label = isPositive ? dirLabels[ax][0] : dirLabels[ax][1];
|
|
27882
|
-
lines.push(` ${a.name} is ${label} ${b.name} (gap: ${n.gap.toFixed(0)}mm)`);
|
|
27883
|
-
}
|
|
27884
|
-
}
|
|
27885
|
-
const seen = /* @__PURE__ */ new Set();
|
|
27886
|
-
const deduped = [];
|
|
27887
|
-
for (const line of lines) {
|
|
27888
|
-
if (line.includes("COLLISION")) {
|
|
27889
|
-
deduped.push(line);
|
|
27890
|
-
continue;
|
|
27891
|
-
}
|
|
27892
|
-
const match = line.match(/^\s+(.+?) is (?:LEFT of|RIGHT of|IN FRONT of|BEHIND|BELOW|ABOVE) (.+?) \(gap: (\d+)mm\)/);
|
|
27893
|
-
if (match) {
|
|
27894
|
-
const key = [match[1], match[2]].sort().join("|") + "|" + match[3];
|
|
27895
|
-
if (!seen.has(key)) {
|
|
27896
|
-
seen.add(key);
|
|
27897
|
-
deduped.push(line);
|
|
27898
|
-
}
|
|
27899
|
-
} else {
|
|
27900
|
-
deduped.push(line);
|
|
27901
|
-
}
|
|
27902
|
-
}
|
|
27903
|
-
const groups = /* @__PURE__ */ new Map();
|
|
27904
|
-
for (const e of entries) {
|
|
27905
|
-
if (!e.groupName) continue;
|
|
27906
|
-
const g = groups.get(e.groupName) || { min: [Infinity, Infinity, Infinity], max: [-Infinity, -Infinity, -Infinity] };
|
|
27907
|
-
for (let ax = 0; ax < 3; ax++) {
|
|
27908
|
-
g.min[ax] = Math.min(g.min[ax], e.min[ax]);
|
|
27909
|
-
g.max[ax] = Math.max(g.max[ax], e.max[ax]);
|
|
27910
|
-
}
|
|
27911
|
-
groups.set(e.groupName, g);
|
|
27912
|
-
}
|
|
27913
|
-
if (groups.size > 1) {
|
|
27914
|
-
deduped.push("");
|
|
27915
|
-
deduped.push(" Groups:");
|
|
27916
|
-
const groupNames = [...groups.keys()];
|
|
27917
|
-
for (let i = 0; i < groupNames.length; i++) {
|
|
27918
|
-
const aName = groupNames[i], a = groups.get(aName);
|
|
27919
|
-
for (let j = i + 1; j < groupNames.length; j++) {
|
|
27920
|
-
const bName = groupNames[j], b = groups.get(bName);
|
|
27921
|
-
for (let ax = 0; ax < 3; ax++) {
|
|
27922
|
-
if (a.max[ax] < b.min[ax]) {
|
|
27923
|
-
const gap = b.min[ax] - a.max[ax];
|
|
27924
|
-
if (gap <= proximityThreshold) {
|
|
27925
|
-
const label = dirLabels[ax][0];
|
|
27926
|
-
deduped.push(` ${aName} is ${label} ${bName} (gap: ${gap.toFixed(0)}mm)`);
|
|
27927
|
-
}
|
|
27928
|
-
} else if (b.max[ax] < a.min[ax]) {
|
|
27929
|
-
const gap = a.min[ax] - b.max[ax];
|
|
27930
|
-
if (gap <= proximityThreshold) {
|
|
27931
|
-
const label = dirLabels[ax][1];
|
|
27932
|
-
deduped.push(` ${aName} is ${label} ${bName} (gap: ${gap.toFixed(0)}mm)`);
|
|
27933
|
-
}
|
|
27934
|
-
}
|
|
27935
|
-
}
|
|
27936
|
-
}
|
|
27937
|
-
}
|
|
27938
|
-
}
|
|
27939
|
-
return deduped;
|
|
27940
|
-
}
|
|
27941
28259
|
function parseParamFlags2(argv) {
|
|
27942
28260
|
const overrides = {};
|
|
27943
28261
|
const consumed = /* @__PURE__ */ new Set();
|
|
@@ -27956,9 +28274,9 @@ function parseParamFlags2(argv) {
|
|
|
27956
28274
|
}
|
|
27957
28275
|
return { overrides, consumed };
|
|
27958
28276
|
}
|
|
27959
|
-
function
|
|
28277
|
+
function usage23() {
|
|
27960
28278
|
console.error(
|
|
27961
|
-
"Usage: forgecad run <model.forge.js|asset.stl|asset.obj|asset.3mf|asset.step|asset.stp> [--details] [--history] [--features] [--connectivity] [--connectivity-tolerance <mm>] [--
|
|
28279
|
+
"Usage: forgecad run <model.forge.js|asset.stl|asset.obj|asset.3mf|asset.step|asset.stp> [--details] [--history] [--features] [--connectivity] [--connectivity-tolerance <mm>] [--param Key=Value] [--debug-imports] [--verbose|-v] [--backend manifold|occt|truck] [--quality live|default|high] [--solver-profile] [--solver-debug-out <dir>]"
|
|
27962
28280
|
);
|
|
27963
28281
|
process.exit(1);
|
|
27964
28282
|
}
|
|
@@ -28115,7 +28433,13 @@ function printCompactObjectSummary(objects, focusSummary) {
|
|
|
28115
28433
|
async function runScriptCli(argv = process.argv.slice(2)) {
|
|
28116
28434
|
if (argv.includes("--full")) {
|
|
28117
28435
|
console.error("`forgecad run --full` has been removed.");
|
|
28118
|
-
console.error("Use explicit diagnostics: `--details --history --features --solver-profile
|
|
28436
|
+
console.error("Use explicit diagnostics: `--details --history --features --solver-profile`.");
|
|
28437
|
+
process.exit(1);
|
|
28438
|
+
}
|
|
28439
|
+
const removedSpatialFlag = argv.find((arg) => arg === "--spatial" || arg.startsWith("--spatial="));
|
|
28440
|
+
if (removedSpatialFlag) {
|
|
28441
|
+
console.error("`forgecad run --spatial` has been removed.");
|
|
28442
|
+
console.error("Use `forgecad inspect fit interference <model>` for collision evidence or `forgecad inspect physical gaps <model>` for spatial gap evidence.");
|
|
28119
28443
|
process.exit(1);
|
|
28120
28444
|
}
|
|
28121
28445
|
const { overrides: paramCliOverrides, consumed: paramConsumed } = parseParamFlags2(argv);
|
|
@@ -28142,12 +28466,11 @@ async function runScriptCli(argv = process.argv.slice(2)) {
|
|
|
28142
28466
|
const explicitBackend = parseBackendArg2(argv);
|
|
28143
28467
|
const quality = parseQualityArg2(argv);
|
|
28144
28468
|
const solverDebugOut = parseRequiredArg(argv, "--solver-debug-out");
|
|
28145
|
-
const { mode: spatialMode, consumed: spatialConsumed, explicit: spatialExplicit } = parseSpatialMode(argv, "off");
|
|
28146
28469
|
const positional = argv.filter(
|
|
28147
|
-
(arg, i) => !paramConsumed.has(i) && !focusConsumed.has(i) && !connectivityConsumed.has(i) &&
|
|
28470
|
+
(arg, i) => !paramConsumed.has(i) && !focusConsumed.has(i) && !connectivityConsumed.has(i) && arg !== "--details" && arg !== "--history" && arg !== "--features" && arg !== "--solver-profile" && arg !== "--debug-imports" && arg !== "--journeys" && arg !== "--journeys-json" && arg !== "--verbose" && arg !== "-v" && arg !== "--backend" && argv[i - 1] !== "--backend" && arg !== "--quality" && argv[i - 1] !== "--quality" && arg !== "-q" && argv[i - 1] !== "-q" && arg !== "--solver-debug-out" && argv[i - 1] !== "--solver-debug-out"
|
|
28148
28471
|
);
|
|
28149
28472
|
const scriptPath = positional[0];
|
|
28150
|
-
if (!scriptPath)
|
|
28473
|
+
if (!scriptPath) usage23();
|
|
28151
28474
|
let activeBackend = CLI_DEFAULT_BACKEND;
|
|
28152
28475
|
try {
|
|
28153
28476
|
if (solverDebugOut) {
|
|
@@ -28319,8 +28642,7 @@ async function runScriptCli(argv = process.argv.slice(2)) {
|
|
|
28319
28642
|
console.log(` ${log.args.join(" ")}`);
|
|
28320
28643
|
}
|
|
28321
28644
|
}
|
|
28322
|
-
const
|
|
28323
|
-
const entries = needsShapeEntries ? visibleObjects.filter((o) => o.shape).map((o) => {
|
|
28645
|
+
const entries = connectivityEnabled ? visibleObjects.filter((o) => o.shape).map((o) => {
|
|
28324
28646
|
const bb = o.shape.boundingBox();
|
|
28325
28647
|
return {
|
|
28326
28648
|
id: o.id,
|
|
@@ -28340,18 +28662,6 @@ async function runScriptCli(argv = process.argv.slice(2)) {
|
|
|
28340
28662
|
const connectivity = analyzePhysicalConnectivity2(entries, connectivityOptions);
|
|
28341
28663
|
for (const line of formatPhysicalConnectivity(connectivity)) console.log(line);
|
|
28342
28664
|
}
|
|
28343
|
-
if (entries.length > 1 && spatialMode !== "off") {
|
|
28344
|
-
console.log(`
|
|
28345
|
-
\u2713 Spatial analysis:`);
|
|
28346
|
-
const spatialLines = analyzeSpatial(entries, spatialMode);
|
|
28347
|
-
for (const line of spatialLines) console.log(line);
|
|
28348
|
-
if (spatialLines.length === 0) {
|
|
28349
|
-
console.log(` (no collisions, all objects well-separated)`);
|
|
28350
|
-
}
|
|
28351
|
-
} else if (spatialExplicit && visibleObjects.filter((o) => o.shape).length > 1 && spatialMode === "off") {
|
|
28352
|
-
console.log(`
|
|
28353
|
-
\u2713 Spatial analysis: skipped (--spatial off)`);
|
|
28354
|
-
}
|
|
28355
28665
|
console.log(
|
|
28356
28666
|
`\u2713 Params: ${result.params.map((p) => {
|
|
28357
28667
|
const label = p.choices ? `${p.choices[p.value]}` : `${p.value}`;
|
|
@@ -28512,7 +28822,7 @@ async function runScriptCli(argv = process.argv.slice(2)) {
|
|
|
28512
28822
|
// cli/forge-render-section.ts
|
|
28513
28823
|
import { writeFile as writeFile10 } from "fs/promises";
|
|
28514
28824
|
import { basename as basename16, extname as extname11, resolve as resolve39 } from "path";
|
|
28515
|
-
function
|
|
28825
|
+
function usage24() {
|
|
28516
28826
|
console.error(
|
|
28517
28827
|
"Usage: forgecad render section <model.forge.js|asset.stl|asset.obj|asset.3mf|asset.step|asset.stp> [output.svg|.png] [--param Key=Value] [--plane XY|XZ|YZ] [--offset <number>] [--size <px>] [--edges <off|thin|bold>] [--chrome-path <path>] [--background <color>]"
|
|
28518
28828
|
);
|
|
@@ -28573,12 +28883,12 @@ async function runRenderSectionCli(argv = process.argv.slice(2)) {
|
|
|
28573
28883
|
background = argv[++i];
|
|
28574
28884
|
} else if (argv[i].startsWith("-")) {
|
|
28575
28885
|
console.error(`Unknown option: ${argv[i]}`);
|
|
28576
|
-
|
|
28886
|
+
usage24();
|
|
28577
28887
|
} else {
|
|
28578
28888
|
args.push(argv[i]);
|
|
28579
28889
|
}
|
|
28580
28890
|
}
|
|
28581
|
-
if (args.length === 0)
|
|
28891
|
+
if (args.length === 0) usage24();
|
|
28582
28892
|
scriptPath = args[0];
|
|
28583
28893
|
const wantsPng = args[1] ? extname11(args[1]).toLowerCase() === ".png" : false;
|
|
28584
28894
|
outputPath = args[1] || defaultOutput(scriptPath, wantsPng ? "png" : "svg");
|
|
@@ -28919,7 +29229,7 @@ var RENDER_OPTIONS = [
|
|
|
28919
29229
|
valueLabel: "<classic|studio|fast|glass|inspection|precision|hybrid|scan>",
|
|
28920
29230
|
values: RENDER_STYLE_VALUES
|
|
28921
29231
|
},
|
|
28922
|
-
{ name: "--scan-granularity", description: "Scan cells across the scene longest axis", argument: "required", valueLabel: "<12-
|
|
29232
|
+
{ name: "--scan-granularity", description: "Scan cells across the scene longest axis", argument: "required", valueLabel: "<12-144>" },
|
|
28923
29233
|
{ name: "--port", description: "Vite dev server port", argument: "required", valueLabel: "<n>" },
|
|
28924
29234
|
{ name: "--fresh-server", description: "Start a fresh renderer instead of reusing an existing one" },
|
|
28925
29235
|
{
|
|
@@ -28931,6 +29241,51 @@ var RENDER_OPTIONS = [
|
|
|
28931
29241
|
},
|
|
28932
29242
|
{ name: "--output", description: "Output file path", argument: "required", valueLabel: "<path>", valueKind: "png" }
|
|
28933
29243
|
];
|
|
29244
|
+
var LS_OPTIONS = [
|
|
29245
|
+
{ name: "--tree", description: "Print targets as a compact object tree" },
|
|
29246
|
+
{ name: "--long", description: "Include geometry metrics such as bounds, volume, area, bodies, and triangle counts" },
|
|
29247
|
+
{ name: "--json", description: "Print machine-readable target inventory" },
|
|
29248
|
+
{ name: "--compact", description: "Minify JSON output" },
|
|
29249
|
+
{
|
|
29250
|
+
name: "--kind",
|
|
29251
|
+
description: "Filter targets by kind",
|
|
29252
|
+
argument: "required",
|
|
29253
|
+
valueLabel: "<shape|sketch|sdf|toolpath|mock|object>"
|
|
29254
|
+
},
|
|
29255
|
+
...PARAM_OPTIONS,
|
|
29256
|
+
{
|
|
29257
|
+
name: "--backend",
|
|
29258
|
+
description: "Geometry backend",
|
|
29259
|
+
argument: "required",
|
|
29260
|
+
valueLabel: "<manifold|occt|truck>",
|
|
29261
|
+
values: BACKEND_VALUES
|
|
29262
|
+
},
|
|
29263
|
+
{
|
|
29264
|
+
name: "--quality",
|
|
29265
|
+
description: "Geometry quality preset",
|
|
29266
|
+
argument: "required",
|
|
29267
|
+
valueLabel: "<live|default|high>",
|
|
29268
|
+
values: QUALITY_VALUES
|
|
29269
|
+
}
|
|
29270
|
+
];
|
|
29271
|
+
var SHOW_OPTIONS = [
|
|
29272
|
+
{
|
|
29273
|
+
name: "--from",
|
|
29274
|
+
description: "Quick camera direction",
|
|
29275
|
+
argument: "required",
|
|
29276
|
+
valueLabel: "<front|back|side|right|top|iso|az:el|az:el:dist>",
|
|
29277
|
+
values: RENDER_ANGLE_VALUES
|
|
29278
|
+
},
|
|
29279
|
+
{ name: "--out", description: "Output file path", argument: "required", valueLabel: "<path>", valueKind: "png" },
|
|
29280
|
+
{
|
|
29281
|
+
name: "--backend",
|
|
29282
|
+
description: "Geometry backend",
|
|
29283
|
+
argument: "required",
|
|
29284
|
+
valueLabel: "<manifold|occt|truck>",
|
|
29285
|
+
values: BACKEND_VALUES
|
|
29286
|
+
},
|
|
29287
|
+
...RENDER_OPTIONS.filter((option) => option.name !== "--focus" && option.name !== "--hide")
|
|
29288
|
+
];
|
|
28934
29289
|
var INSPECT_EVIDENCE_OPTIONS = [
|
|
28935
29290
|
...PARAM_OPTIONS,
|
|
28936
29291
|
{
|
|
@@ -29972,13 +30327,61 @@ var commands = [
|
|
|
29972
30327
|
hidden: true,
|
|
29973
30328
|
run: async (args) => runHiddenCompletionCli(args, commands)
|
|
29974
30329
|
},
|
|
30330
|
+
{
|
|
30331
|
+
group: "Modeling",
|
|
30332
|
+
path: ["ls"],
|
|
30333
|
+
summary: "List targetable scene objects for a model.",
|
|
30334
|
+
description: "Runs the model headlessly and prints the exact object paths that CLI tools can target. Use this before focused renders or inspections when object names, groups, or assembly paths are not obvious.\n\nThe default output is a compact line-oriented list. Use `--tree` for an indented hierarchy, `--long` for geometry metrics, or `--json` for automation.",
|
|
30335
|
+
usage: [
|
|
30336
|
+
"forgecad ls <model.forge.js|asset.stl|asset.obj|asset.3mf|asset.step|asset.stp> [target] [--tree] [--long] [--json] [--kind shape,sketch,mock] [--param Key=Value] [--backend manifold|occt|truck] [--quality live|default|high]"
|
|
30337
|
+
],
|
|
30338
|
+
examples: [
|
|
30339
|
+
"forgecad ls examples/api/static-assembly-connectors.forge.js",
|
|
30340
|
+
"forgecad ls examples/api/static-assembly-connectors.forge.js --tree",
|
|
30341
|
+
"forgecad ls examples/api/static-assembly-connectors.forge.js Bench",
|
|
30342
|
+
'forgecad ls examples/api/static-assembly-connectors.forge.js "Bench/Slat0" --long',
|
|
30343
|
+
"forgecad ls examples/api/static-assembly-connectors.forge.js --json"
|
|
30344
|
+
],
|
|
30345
|
+
completion: {
|
|
30346
|
+
options: LS_OPTIONS,
|
|
30347
|
+
positionals: [
|
|
30348
|
+
{ description: "Forge script or CAD asset", valueKind: "renderable" },
|
|
30349
|
+
{ description: "optional target path, object name, id, group, or glob" }
|
|
30350
|
+
]
|
|
30351
|
+
},
|
|
30352
|
+
run: runLsCli
|
|
30353
|
+
},
|
|
30354
|
+
{
|
|
30355
|
+
group: "Modeling",
|
|
30356
|
+
path: ["show"],
|
|
30357
|
+
summary: "Render a quick target-focused viewport PNG.",
|
|
30358
|
+
description: "The main quick visual path for agents. Pass a model and, optionally, a target path from `forgecad ls`; ForgeCAD resolves the target and renders that object or group through the existing viewport renderer. Use `--from` for fast camera directions, or pass the lower-level render camera flags when you need exact reproducibility.\n\nWithout a target, `show` renders the whole scene and behaves like a shorter, intent-first wrapper around `render 3d`.",
|
|
30359
|
+
usage: [
|
|
30360
|
+
"forgecad show <model.forge.js|asset.stl|asset.obj|asset.3mf|asset.step|asset.stp> [target] [output.png] [--from front|back|side|right|top|iso|az:el|az:el:dist] [--out output.png] [--param Key=Value] [--backend manifold|occt|truck] [render options]"
|
|
30361
|
+
],
|
|
30362
|
+
examples: [
|
|
30363
|
+
"forgecad show examples/api/static-assembly-connectors.forge.js",
|
|
30364
|
+
"forgecad show examples/api/static-assembly-connectors.forge.js Bench",
|
|
30365
|
+
'forgecad show examples/api/static-assembly-connectors.forge.js "Bench/Slat0" --from front --out slat-front.png',
|
|
30366
|
+
'forgecad show model.forge.js --camera "proj=perspective;pos=200,-160,120;target=0,0,20;up=0,0,1;fov=38"'
|
|
30367
|
+
],
|
|
30368
|
+
completion: {
|
|
30369
|
+
options: SHOW_OPTIONS,
|
|
30370
|
+
positionals: [
|
|
30371
|
+
{ description: "Forge script or CAD asset", valueKind: "renderable" },
|
|
30372
|
+
{ description: "optional target path, object name, id, group, or glob" },
|
|
30373
|
+
{ description: "output PNG path", valueKind: "png" }
|
|
30374
|
+
]
|
|
30375
|
+
},
|
|
30376
|
+
run: runShowCli
|
|
30377
|
+
},
|
|
29975
30378
|
{
|
|
29976
30379
|
group: "Modeling",
|
|
29977
30380
|
path: ["run"],
|
|
29978
|
-
summary: "Execute a Forge script quickly and print the inner-loop build summary:
|
|
29979
|
-
description: "The fast validation command. Runs your script with the real geometry kernel (no browser needed) and reports whether it built,
|
|
30381
|
+
summary: "Execute a Forge script quickly and print the inner-loop build summary: build count, verification results, parameters, and timing.",
|
|
30382
|
+
description: "The fast validation command. Runs your script with the real geometry kernel (no browser needed) and reports whether it built, how many objects came back, any `verify.*` results, parameter values, script logs, and elapsed script time. This is the command agents should run frequently while editing a model.\n\n**Fast by default** \u2014 a bare `forgecad run model.forge.js` does not compute per-object volumes, bounding boxes, construction history, feature tallies, or solver profiles. Those run diagnostics are useful, but they are no longer part of the hot path.\n\n**Opt-in diagnostics** \u2014 use `--details` for volume/bounding-box/object geometry summaries, `--history` for the construction tree, `--features` for feature tallies, or `--solver-profile` for constraint solver timing. Use `inspect fit interference`, `inspect physical gaps`, or `inspect mechanical-integrity --collisions` for spatial and collision evidence.\n\n**Verification results** \u2014 runs any `verify.*` checks in the script and reports pass/fail with expected vs actual values. Verification failures remain non-fatal so the model can still render and be inspected.\n\n**Physical connectivity** \u2014 pass `--connectivity` to list physically connected components across visible objects. Overlapping bbox candidates are checked with exact geometry by default, while bbox-only contact is treated as evidence rather than proof of one connected component. This helps answer whether the model is one continuous assembly or several separate islands.\n\n**Quality preset** \u2014 pass `--quality live|default|high` to select the same geometry quality profile used by the editor and export tools. `live` is the fastest preset for large audit models.\n\n**Direct CAD inputs** \u2014 pass `.stl`, `.obj`, `.3mf`, `.step`, or `.stp` directly when you just want to inspect an external asset. Mesh files are imported with `importMesh(...)`; STEP/STP files are imported with `importStep(...)` and auto-select OCCT unless you pass `--backend`.\n\nFor deeper confidence gates, prefer `forgecad inspect mechanical-integrity`, `forgecad check print`, or targeted evidence commands such as `forgecad inspect fit interference` instead of turning `run` back into a catch-all audit command.",
|
|
29980
30383
|
usage: [
|
|
29981
|
-
"forgecad run <model.forge.js|asset.stl|asset.obj|asset.3mf|asset.step|asset.stp> [--details] [--history] [--features] [--connectivity] [--connectivity-tolerance <mm>] [--
|
|
30384
|
+
"forgecad run <model.forge.js|asset.stl|asset.obj|asset.3mf|asset.step|asset.stp> [--details] [--history] [--features] [--connectivity] [--connectivity-tolerance <mm>] [--focus [names]] [--hide names] [--journeys] [--journeys-json] [--param Key=Value] [--debug-imports] [--verbose] [--backend manifold|occt|truck] [--quality live|default|high] [--solver-profile] [--solver-debug-out <dir>]"
|
|
29982
30385
|
],
|
|
29983
30386
|
examples: [
|
|
29984
30387
|
"forgecad run examples/api/static-assembly-connectors.forge.js",
|
|
@@ -29986,7 +30389,6 @@ var commands = [
|
|
|
29986
30389
|
'forgecad run examples/api/static-assembly-connectors.forge.js --focus "Bench.Slat*"',
|
|
29987
30390
|
'forgecad run examples/api/static-assembly-connectors.forge.js --hide "Bench.Slat0,Bench.Slat1"',
|
|
29988
30391
|
"forgecad run examples/api/static-assembly-connectors.forge.js --details --history",
|
|
29989
|
-
"forgecad run examples/api/static-assembly-connectors.forge.js --spatial bounded",
|
|
29990
30392
|
"forgecad run examples/products/cup.forge.js --connectivity",
|
|
29991
30393
|
"forgecad run examples/products/cup.forge.js --journeys",
|
|
29992
30394
|
"forgecad run examples/products/cup.forge.js --backend occt",
|
|
@@ -30017,17 +30419,6 @@ var commands = [
|
|
|
30017
30419
|
argument: "required",
|
|
30018
30420
|
valueLabel: "<mm>"
|
|
30019
30421
|
},
|
|
30020
|
-
{
|
|
30021
|
-
name: "--spatial",
|
|
30022
|
-
description: "Spatial diagnostics mode (default: off)",
|
|
30023
|
-
argument: "required",
|
|
30024
|
-
valueLabel: "<bounded|exact|off>",
|
|
30025
|
-
values: [
|
|
30026
|
-
{ value: "bounded", description: "Exact checks only for bounded scene sizes" },
|
|
30027
|
-
{ value: "exact", description: "Exhaustive pairwise exact collision intersections" },
|
|
30028
|
-
{ value: "off", description: "Skip spatial diagnostics" }
|
|
30029
|
-
]
|
|
30030
|
-
},
|
|
30031
30422
|
{ name: "--debug-imports", description: "Print the import trace" },
|
|
30032
30423
|
{ name: "--journeys", description: "Print model journey summaries declared with scene({ journeys })" },
|
|
30033
30424
|
{ name: "--journeys-json", description: "Emit machine-readable journey metadata and diagnostics only" },
|
|
@@ -30147,7 +30538,9 @@ var commands = [
|
|
|
30147
30538
|
path: ["render", "wireframe"],
|
|
30148
30539
|
summary: "Render a Forge scene as a wireframe (edges only, no shading).",
|
|
30149
30540
|
description: "Same as `render 3d` but renders only the edge geometry \u2014 no shaded surfaces. Useful for construction-style documentation or highlighting structural features without material detail.",
|
|
30150
|
-
usage: [
|
|
30541
|
+
usage: [
|
|
30542
|
+
"forgecad render wireframe <model.forge.js|asset.stl|asset.obj|asset.3mf|asset.step|asset.stp> [output.png] [--param Key=Value] [options]"
|
|
30543
|
+
],
|
|
30151
30544
|
examples: [
|
|
30152
30545
|
"forgecad render wireframe examples/products/cup.forge.js",
|
|
30153
30546
|
"forgecad render wireframe examples/products/cup.forge.js --camera iso"
|
|
@@ -30198,7 +30591,9 @@ var commands = [
|
|
|
30198
30591
|
path: ["render", "hq"],
|
|
30199
30592
|
summary: "High-quality render via Blender Cycles \u2014 path-traced, HDRI, material presets.",
|
|
30200
30593
|
description: "Exports the scene to Blender and renders with Cycles (path tracer). Requires Blender installed and on PATH.\n\nChoose a `--preset` for the look: `studio` (neutral product shot), `dramatic` (high-contrast), `clay` (matte, no color), `glass`, `metallic`, `toon`, `xray`, `normals`, `silhouette`, and more. Control quality vs speed with `--samples` (default 256). Use `--view`, `--camera`, `--camera-json`, or `--scene <file>` for still camera control, matching `render 3d`. Use `--transparent` for a transparent background (compositing-ready).\n\nOutput defaults to `<script-name>-hq.png`. Great for documentation, marketing renders, and social media.",
|
|
30201
|
-
usage: [
|
|
30594
|
+
usage: [
|
|
30595
|
+
"forgecad render hq <model.forge.js|asset.stl|asset.obj|asset.3mf|asset.step|asset.stp> [output.png] [--param Key=Value] [options]"
|
|
30596
|
+
],
|
|
30202
30597
|
examples: [
|
|
30203
30598
|
"forgecad render hq examples/products/cup.forge.js",
|
|
30204
30599
|
"forgecad render hq examples/products/cup.forge.js hero.png --preset dramatic --samples 1024",
|
|
@@ -31461,7 +31856,9 @@ var commands = [
|
|
|
31461
31856
|
path: ["inspect", "replay"],
|
|
31462
31857
|
summary: "Replay a saved section inspection result on a source model.",
|
|
31463
31858
|
description: "Reads a previous `forgecad inspect section` result, reruns the same section and ray rulers on the requested source, and writes a fresh unique result directory with measurement deltas against the original.",
|
|
31464
|
-
usage: [
|
|
31859
|
+
usage: [
|
|
31860
|
+
"forgecad inspect replay <result.json> --source <model.forge.js|asset.stl|asset.obj|asset.3mf|asset.step|asset.stp> [--param Key=Value] [options]"
|
|
31861
|
+
],
|
|
31465
31862
|
examples: [
|
|
31466
31863
|
"forgecad inspect replay outputs/inspect/2026-05-28T14-32-09.184Z__section__bearing__a8f3c1/result.json --source submission/main.forge.js"
|
|
31467
31864
|
],
|
|
@@ -31671,7 +32068,7 @@ var commands = [
|
|
|
31671
32068
|
{ name: "--update", description: "Regenerate compiler snapshots" }
|
|
31672
32069
|
]
|
|
31673
32070
|
},
|
|
31674
|
-
run: async (args) => (await import("./check-compiler-
|
|
32071
|
+
run: async (args) => (await import("./check-compiler-U5SOPN7X.js")).runCheckCompilerCli(args)
|
|
31675
32072
|
},
|
|
31676
32073
|
{
|
|
31677
32074
|
group: "Checks",
|
|
@@ -31694,7 +32091,7 @@ var commands = [
|
|
|
31694
32091
|
{ name: "--update", description: "Regenerate query-propagation snapshots" }
|
|
31695
32092
|
]
|
|
31696
32093
|
},
|
|
31697
|
-
run: async (args) => (await import("./check-query-propagation-
|
|
32094
|
+
run: async (args) => (await import("./check-query-propagation-XOKNSSYU.js")).runCheckQueryPropagationCli(args)
|
|
31698
32095
|
},
|
|
31699
32096
|
{
|
|
31700
32097
|
group: "Checks",
|
|
@@ -31929,64 +32326,37 @@ function readVersion() {
|
|
|
31929
32326
|
return "0.0.0";
|
|
31930
32327
|
}
|
|
31931
32328
|
}
|
|
31932
|
-
var
|
|
31933
|
-
|
|
31934
|
-
|
|
31935
|
-
"
|
|
31936
|
-
"
|
|
31937
|
-
"
|
|
31938
|
-
"
|
|
31939
|
-
"
|
|
31940
|
-
"
|
|
31941
|
-
"
|
|
31942
|
-
"
|
|
31943
|
-
|
|
31944
|
-
|
|
31945
|
-
|
|
31946
|
-
"
|
|
31947
|
-
"
|
|
31948
|
-
"
|
|
31949
|
-
"
|
|
31950
|
-
"
|
|
31951
|
-
"
|
|
31952
|
-
"
|
|
31953
|
-
"
|
|
31954
|
-
"
|
|
31955
|
-
"
|
|
31956
|
-
"
|
|
31957
|
-
"
|
|
31958
|
-
"
|
|
31959
|
-
"
|
|
31960
|
-
"
|
|
31961
|
-
"
|
|
31962
|
-
"
|
|
31963
|
-
"inspect section",
|
|
31964
|
-
"inspect replay",
|
|
31965
|
-
"inspect visual",
|
|
31966
|
-
"inspect visual image",
|
|
31967
|
-
"inspect visual cutaway",
|
|
31968
|
-
"inspect visual depth",
|
|
31969
|
-
"inspect visual normals",
|
|
31970
|
-
"inspect visual objects",
|
|
31971
|
-
"inspect surface",
|
|
31972
|
-
"inspect surface zebra",
|
|
31973
|
-
"inspect surface roughness",
|
|
31974
|
-
"inspect physical",
|
|
31975
|
-
"inspect physical components",
|
|
31976
|
-
"inspect physical floating",
|
|
31977
|
-
"inspect physical gaps",
|
|
31978
|
-
"inspect fit",
|
|
31979
|
-
"inspect fit interference",
|
|
31980
|
-
"inspect manufacture",
|
|
31981
|
-
"inspect manufacture thickness",
|
|
31982
|
-
"inspect compare",
|
|
31983
|
-
"inspect compare overlay",
|
|
31984
|
-
"inspect sections at",
|
|
31985
|
-
"inspect sections stack",
|
|
31986
|
-
"inspect sections sample",
|
|
31987
|
-
"inspect mechanical-integrity",
|
|
31988
|
-
"project file",
|
|
31989
|
-
"project shares"
|
|
32329
|
+
var AUTH_REQUIRED_COMMANDS = /* @__PURE__ */ new Set([
|
|
32330
|
+
// Hosted project, publish, token, and account-license mutations touch ForgeCAD server state.
|
|
32331
|
+
// Local modeling, inspection, export, and skill setup commands stay available without sign-in.
|
|
32332
|
+
"project init",
|
|
32333
|
+
"project clone",
|
|
32334
|
+
"project pull",
|
|
32335
|
+
"project push",
|
|
32336
|
+
"project status",
|
|
32337
|
+
"project list",
|
|
32338
|
+
"project publish",
|
|
32339
|
+
"project info",
|
|
32340
|
+
"project rename",
|
|
32341
|
+
"project set-visibility",
|
|
32342
|
+
"project delete",
|
|
32343
|
+
"project members",
|
|
32344
|
+
"project add-member",
|
|
32345
|
+
"project remove-member",
|
|
32346
|
+
"project set-role",
|
|
32347
|
+
"project file list",
|
|
32348
|
+
"project file read",
|
|
32349
|
+
"project file save",
|
|
32350
|
+
"project file delete",
|
|
32351
|
+
"project file rename",
|
|
32352
|
+
"project file mkdir",
|
|
32353
|
+
"project file copy",
|
|
32354
|
+
"project shares list",
|
|
32355
|
+
"project shares delete",
|
|
32356
|
+
"token create",
|
|
32357
|
+
"token list",
|
|
32358
|
+
"token revoke",
|
|
32359
|
+
"license activate"
|
|
31990
32360
|
]);
|
|
31991
32361
|
var LONG_RUNNING_COMMANDS = /* @__PURE__ */ new Set(["dev", "studio", "web"]);
|
|
31992
32362
|
var INTERNAL_CHECK_COMMANDS = /* @__PURE__ */ new Set([
|
|
@@ -32036,6 +32406,8 @@ var TOPIC_DESCRIPTIONS = {
|
|
|
32036
32406
|
};
|
|
32037
32407
|
var ROOT_WORKFLOWS = [
|
|
32038
32408
|
["forgecad run <model.forge.js>", "Execute a model and print the inner-loop build summary."],
|
|
32409
|
+
["forgecad ls <model.forge.js>", "List targetable object paths before narrowing a render or inspection."],
|
|
32410
|
+
["forgecad show <model.forge.js> [target]", "Render a quick viewport PNG for the whole scene or a target."],
|
|
32039
32411
|
["forgecad check print <model.forge.js>", "Catch printability problems before export."],
|
|
32040
32412
|
["forgecad render 3d <model.forge.js> --output preview.png", "Render a viewport PNG."],
|
|
32041
32413
|
["forgecad export step <model.forge.js> --output part.step", "Export exact CAD for downstream tools."],
|
|
@@ -32045,7 +32417,7 @@ var ROOT_HELP_GROUPS = [
|
|
|
32045
32417
|
{ heading: "Studio", paths: [["studio"], ["dev"], ["web"]] },
|
|
32046
32418
|
{
|
|
32047
32419
|
heading: "Modeling",
|
|
32048
|
-
paths: [["run"], ["render"], ["capture"], ["check"], ["compare"], ["inspect"]]
|
|
32420
|
+
paths: [["run"], ["ls"], ["show"], ["render"], ["capture"], ["check"], ["compare"], ["inspect"]]
|
|
32049
32421
|
},
|
|
32050
32422
|
{ heading: "Export", paths: [["export"], ["cut-list"], ["link"]] },
|
|
32051
32423
|
{
|
|
@@ -32073,7 +32445,7 @@ function commandKey(commandPath) {
|
|
|
32073
32445
|
return commandPath.join(" ");
|
|
32074
32446
|
}
|
|
32075
32447
|
function commandRequiresCliAuth(commandPath) {
|
|
32076
|
-
return
|
|
32448
|
+
return AUTH_REQUIRED_COMMANDS.has(commandKey(commandPath));
|
|
32077
32449
|
}
|
|
32078
32450
|
function isLongRunningCommand(commandPath) {
|
|
32079
32451
|
return LONG_RUNNING_COMMANDS.has(commandKey(commandPath));
|
|
@@ -32505,7 +32877,11 @@ function printMovedSharesTopicMessage(argv) {
|
|
|
32505
32877
|
}
|
|
32506
32878
|
function printRemovedRunFullFlagMessage() {
|
|
32507
32879
|
console.error("`forgecad run --full` has been removed.");
|
|
32508
|
-
console.error("Use explicit diagnostics: `--details --history --features --solver-profile
|
|
32880
|
+
console.error("Use explicit diagnostics: `--details --history --features --solver-profile`.");
|
|
32881
|
+
}
|
|
32882
|
+
function printRemovedRunSpatialFlagMessage() {
|
|
32883
|
+
console.error("`forgecad run --spatial` has been removed.");
|
|
32884
|
+
console.error("Use `forgecad inspect fit interference <model>` for collision evidence or `forgecad inspect physical gaps <model>` for spatial gap evidence.");
|
|
32509
32885
|
}
|
|
32510
32886
|
function printInternalCheckCommandMessage(commandName) {
|
|
32511
32887
|
if (commandName === "params") {
|
|
@@ -32618,6 +32994,11 @@ async function runForgeCadCli(argv = process.argv.slice(2)) {
|
|
|
32618
32994
|
process.exitCode = 1;
|
|
32619
32995
|
return;
|
|
32620
32996
|
}
|
|
32997
|
+
if (argv[0] === "run" && argv.some((arg) => arg === "--spatial" || arg.startsWith("--spatial=")) && !argv.some(isHelpFlag)) {
|
|
32998
|
+
printRemovedRunSpatialFlagMessage();
|
|
32999
|
+
process.exitCode = 1;
|
|
33000
|
+
return;
|
|
33001
|
+
}
|
|
32621
33002
|
const wantsHelp = argv.some(isHelpFlag);
|
|
32622
33003
|
const wantsVersion = argv[0] === "-v" || argv[0] === "--version";
|
|
32623
33004
|
const skipUpdateMachinery = argv[0] === "__complete" || argv[0] === "completion" || wantsVersion || wantsHelp;
|