manifold-3d
Version:
Geometry library for topological robustness
143 lines • 5.01 kB
JavaScript
// Copyright 2024-25 The Manifold Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* Export models out of manifoldCAD.
*
* ManifoldCAD uses [gltf-transform](https://gltf-transform.dev/) internally to
* represent scenes. Exporters must accept in-memory gltf-transform Documents.
*
* Exporters and importers can each accept one or more type of file.
* Each format must have a defined extension and mime type. In the case of
* duplicates, order is not guaranteed. While an implementation may support both
* import and export of a format, this is not required. At the time of writing,
* manifoldCAD supports both import and export of glTF, but only exports 3mf.
*
* @packageDocumentation
* @group ManifoldCAD
* @category Input/Output
*/
import * as GLTFTransform from '@gltf-transform/core';
import { createDefaultPropertyResolver } from '@gltf-transform/functions';
import { UnsupportedFormatError } from "./error.js";
import * as export3MF from "./export-3mf.js";
import * as gltfIO from "./gltf-io.js";
import { findExtension, findMimeType, isNode } from "./util.js";
const exporters = [];
register(gltfIO);
register(export3MF);
const documentToPropertyResolver = new Map();
export const cleanup = () => {
documentToPropertyResolver.clear();
};
function getFormat(identifier) {
const formats = exporters.flatMap(ex => ex.exportFormats);
const format = (findMimeType(identifier, formats) ??
findExtension(identifier, formats));
if (!format)
throw new UnsupportedFormatError(identifier, formats);
return format;
}
function getExporter(identifier) {
const format = typeof identifier === 'string' ? getFormat(identifier) : identifier;
return exporters.find(ex => ex.exportFormats.includes(format));
}
/**
* Returns true if a given extension or mimetype can be exported.
*
* @param filetype
* @param throwOnFailure If true, throw an `UnsupportedFormatException` rather
* than return false.
* @group Management
*/
export function supports(filetype, throwOnFailure) {
if (throwOnFailure)
return !!getFormat(filetype);
try {
return !!getFormat(filetype);
}
catch (e) {
return false;
}
}
/**
* Register an exporter.
*
* Supported formats will be inferred.
* @group Management
* @param exporter
*/
export function register(exporter) {
exporters.push(exporter);
}
/**
* Convert an in-memory GLTF document to a binary Blob.
*
* @param doc The GLTF document.
* @returns A URL encoded blob.
* @group Low Level Functions
*/
export async function toBlob(doc, options = {}) {
if (!(options.mimetype || options.extension)) {
throw new Error('Must specify a mimetype or extension when exporting to a Blob.');
}
const format = getFormat((options.mimetype || options.extension));
const buffer = await getExporter(format).toArrayBuffer(doc, options);
return new Blob([buffer], { type: format.mimetype });
}
/**
* Convert an in-memory GLTF document to an ArrayBuffer.
*
* @param doc The GLTF document.
* @returns A URL encoded blob.
* @group Low Level Functions
*/
export async function toArrayBuffer(doc, options = {}) {
if (!(options.mimetype || options.extension)) {
throw new Error('Must specify a mimetype or extension when exporting to a Buffer.');
}
const format = getFormat((options.mimetype || options.extension));
return await getExporter(format).toArrayBuffer(doc, options);
}
/**
* Write a model to disk.
* @group Low Level Functions
*/
export async function writeFile(filename, doc, options = {}) {
if (!isNode()) {
throw new Error('Must have a filesystem to write files.');
}
const fs = await import('node:fs/promises');
const exporter = getExporter(options.mimetype ?? options.extension ?? filename);
const buffer = await exporter.toArrayBuffer(doc, options);
return await fs.writeFile(filename, new Uint8Array(buffer));
}
/**
* Get or create a PropertyResolver.
*
* These are used to proactively de-duplicate when copying properties into a
* glTF-Transform document.
*
* @hidden
*/
export function getPropertyResolver(dst, src) {
if (!documentToPropertyResolver.has(dst)) {
documentToPropertyResolver.set(dst, new Map());
}
const srcMap = documentToPropertyResolver.get(dst);
if (!srcMap.has(src)) {
srcMap.set(src, createDefaultPropertyResolver(dst, src));
}
return srcMap.get(src);
}
//# sourceMappingURL=export-model.js.map