mcp-3d-printer-server 1.2.13 → 1.2.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.
@@ -11,7 +11,9 @@ import { detectProfilesRoot } from '../slicer/profile-flatten.js';
11
11
  import {
12
12
  BambuCliProfilePreparer,
13
13
  assertSlicedProjectOutput,
14
+ bambuCliFailureReason,
14
15
  buildBambuCliArgs,
16
+ planBambuCliInput,
15
17
  type BambuCliSlicerType,
16
18
  type BambuSliceOptions,
17
19
  } from '../slicer/bambu-cli.js';
@@ -182,6 +184,27 @@ export class STLManipulator extends EventEmitter {
182
184
  return timeoutMs;
183
185
  }
184
186
 
187
+ /**
188
+ * Apply slice_stl's scale and rotations to a copy of the mesh as OrcaSlicer's
189
+ * CLI would, about the model's centre. Orca adds each --rotate* to the
190
+ * object's Euler angles (ModelVolume::rotate), so the result rotates about X,
191
+ * then Y, then Z whatever the argument order, after scaling. The slicer then
192
+ * places the result on the plate.
193
+ */
194
+ private async transformMeshForCli(stlFilePath: string, options: BambuSliceOptions, outputDir: string): Promise<string> {
195
+ const { geometry, boundingBox } = await this.loadSTL(stlFilePath);
196
+ const center = new THREE.Vector3();
197
+ boundingBox.getCenter(center);
198
+ const radians = (degrees: number) => degrees * Math.PI / 180;
199
+ geometry.applyMatrix4(new THREE.Matrix4().makeTranslation(-center.x, -center.y, -center.z));
200
+ if (options.scale !== undefined) geometry.applyMatrix4(new THREE.Matrix4().makeScale(options.scale, options.scale, options.scale));
201
+ if (options.rotateX) geometry.applyMatrix4(new THREE.Matrix4().makeRotationX(radians(options.rotateX)));
202
+ if (options.rotateY) geometry.applyMatrix4(new THREE.Matrix4().makeRotationY(radians(options.rotateY)));
203
+ if (options.rotate) geometry.applyMatrix4(new THREE.Matrix4().makeRotationZ(radians(options.rotate)));
204
+ geometry.applyMatrix4(new THREE.Matrix4().makeTranslation(center.x, center.y, center.z));
205
+ return this.saveSTL(geometry, path.join(outputDir, `${path.basename(stlFilePath, path.extname(stlFilePath))}_transformed.stl`));
206
+ }
207
+
185
208
  /**
186
209
  * Load STL file and return geometry and bounding box
187
210
  */
@@ -1060,6 +1083,7 @@ export class STLManipulator extends EventEmitter {
1060
1083
  }
1061
1084
  options.loadFilaments = legacyFilaments;
1062
1085
  }
1086
+ const cliInput = planBambuCliInput(cliType, is3mf, options);
1063
1087
  const profilesRoot = detectProfilesRoot(slicerPath, cliType);
1064
1088
  const preparer = new BambuCliProfilePreparer(path.join(this.tempDir, 'slicer-profiles'));
1065
1089
  const bundle = await preparer.prepare(
@@ -1072,7 +1096,9 @@ export class STLManipulator extends EventEmitter {
1072
1096
  options
1073
1097
  );
1074
1098
  bambuOutputDir = fs.mkdtempSync(path.join(this.tempDir, `${operationId}-bambu-output-`));
1075
- args = [...buildBambuCliArgs(bundle, bambuOutputDir, exportName, options), stlFilePath];
1099
+ // The transformed copy lives in the run's output directory, which is removed afterwards.
1100
+ const inputPath = cliInput.meshTransformed ? await this.transformMeshForCli(stlFilePath, options, bambuOutputDir) : stlFilePath;
1101
+ args = [...buildBambuCliArgs(bundle, bambuOutputDir, exportName, options, cliInput), inputPath];
1076
1102
  bambuExport = {
1077
1103
  producedPath: path.join(bambuOutputDir, exportName),
1078
1104
  // One folder per operation: concurrent slices of same-named inputs
@@ -1135,12 +1161,14 @@ export class STLManipulator extends EventEmitter {
1135
1161
  if (progressCallback) progressCallback(20, `Executing slicer: ${slicerPath} ${args.join(' ')}`);
1136
1162
  console.error(`Executing: ${slicerPath} ${args.join(' ')}`);
1137
1163
 
1164
+ const cliOutputDir = bambuOutputDir;
1138
1165
  await runSlicerProcess({
1139
1166
  command: slicerPath,
1140
1167
  args,
1141
1168
  timeoutMs: this.resolveSlicerTimeoutMs(),
1142
1169
  slicerType,
1143
1170
  isCancelled: () => !this.activeOperations.get(operationId),
1171
+ failureReason: cliOutputDir ? (exitCode) => bambuCliFailureReason(exitCode, cliOutputDir) : undefined,
1144
1172
  });
1145
1173
 
1146
1174
  if (!this.activeOperations.get(operationId)) {