UNPKG

forma-embedded-view-sdk

Version:

The Forma Embedded View SDK is a JavaScript library for creating custom extensions in Autodesk Forma Site Design (previously Spacemaker).

367 lines (366 loc) 12.1 kB
import type { FormaElement, Transform, Urn } from "forma-elements"; import type { IframeMessenger } from "./iframe-messenger.js"; import { RepresentationsApi } from "./representations.js"; /** * Response format when fetching elements. * * The Urn and FormaElement types can be inspected in the TypeScript type definitions * in your local IDE. */ export type ElementResponse = Record<Urn, FormaElement>; /** * The Elements API allows you to read all elements and create elements in a selection of Forma Site Design element systems. * * @remarks * Available via {@link auto.Forma | Forma}.{@link index.EmbeddedViewSdk.elements | elements}. */ export declare class ElementsApi { #private; floorStack: FloorStackApi; representations: RepresentationsApi; blobs: BlobsApi; /** @hidden */ constructor(iframeMessenger: IframeMessenger); /** * Get an element by urn. * * The method can return multiple elements. This can happen * if the element has children that are bundled with it. * * This method can also be used to include all the transitive children of the element * by setting the recursive parameter to true. * * @example * // Get the root element of the current proposal * const urn = await Forma.proposal.getRootUrn() * const { element, elements } = await Forma.elements.get({ urn }) * * @returns * A map from identifiers to elements. * A single element for the requested element */ get(request: { urn: Urn; recursive?: boolean; }): Promise<{ element: FormaElement; elements: ElementResponse; }>; /** * Get an element hierarchy located at the path relative to the current * root. You default to current proposal by omitting the urn parameter. * * @example * // Get all the building elements of the current proposal * Forma.selection.subscribe(({ paths }) => { * const { element, elements } = await Forma.elements.getByPath({ path: paths[0] }) * }); * * @returns * A map from identifiers to elements. */ getByPath(request: { rootUrn?: Urn; path: string; recursive?: boolean; }): Promise<{ element: FormaElement; elements: ElementResponse; }>; /** * Get the world transform of an element relative to the root element. * * The world transform is the affine transformation matrix that transforms * the element from its local coordinate system to the root coordinate system. * * @example * const { transform } = await Forma.elements.getWorldTransform({ path }) * const { element } = await Forma.elements.getByPath({ path }) * * if (element.representations?.footprint) { * const footprint = await Forma.elements.representations.footprint(element) * * const { data: geojson } = footprint * * void Forma.render.geojson.add({ geojson, transform }) * } * * @param request the path to element from root * @returns The affine transformation matrix of the element */ getWorldTransform(request: { path: string; }): Promise<{ transform: Transform; }>; /** * Allows adding, editing and removing custom properties attached directly to elements. * All properties must live under a namespace which follows `\w{1,20}:\w{1,50}` pattern (e.g.`my:namespace`). * The properties are managed by [JSON Merge Patch](https://datatracker.ietf.org/doc/html/rfc7386) specification. * * Requires edit access to the project. See {@link EmbeddedViewSdk.getCanEdit | getCanEdit} for more info. * * @example * // Add two properties within a namespace to an element and replace its previous urn with the updated urn in a proposal * const addTwoProperties = { * "my:namespace": { * "myFirstProperty": "myFirstValue" * "mySecondProperty": "mySecondValue" * } * } * const result = await Forma.elements.editProperties({urn, propertiesJsonMergePatch: myProperties}); * await Forma.proposal.replaceElement({path, urn: result.urn}) * * @example * // Change value of the first property and remove the second property at the same time * const changeFirstRemoveSecondProperty = { * "my:namespace": { * "myFirstProperty": "veryDifferentValue" * "mySecondProperty": null * } * } * const result = await Forma.elements.editProperties({urn, propertiesJsonMergePatch: changeFirstRemoveSecondProperty}); * await Forma.proposal.replaceElement({path, urn: result.urn}) * * @example * // Remove the whole namespace from the element * const removeWholeNamespace = { * "my:namespace": null * } * const result = await Forma.elements.editProperties({urn, propertiesJsonMergePatch: removeWholeNamespace}); * await Forma.proposal.replaceElement({path, urn: result.urn}) * */ editProperties(request: { urn: Urn; propertiesJsonMergePatch: Record<string, Record<string, any> | null>; }): Promise<{ urn: Urn; }>; } /** A floor represented as an extruded polygon*/ export type Floor = { /** * The footprint of the floor. Must be a counterclockwise polygon. */ polygon: [number, number][]; /** * The height of the floor. Must be a positive number. */ height: number; } | { /** * The id of a plan. */ planId: string; /** * The height of the floor. Must be a positive number. */ height: number; }; /** A floor plan as an collection of extruded units */ export type Plan = { /** * The id of the plan * */ id: string; /** * The unique vertices of the plan. The vertices are used to create the polygons of the units. */ vertices: { id: string; x: number; y: number; }[]; /** * The non-overlapping units of the plan. */ units: Unit[]; }; /** A unit as a extruded polygon with holes */ export type Unit = { /** * The outer ring of the unit. Must be a counterclockwise polygon. * Specified by the ids of the vertices in the enclosing plan. */ polygon: string[]; /** * The program of the unit. */ program?: "CORE" | "CORRIDOR" | "LIVING_UNIT" | "PARKING"; /** * The functionId of the unit. */ functionId?: string; /** * In inner holes of the units. * Must be a counterclockwise polygon. * All holes must be contained in the outer ring given by the polygon. * Specified by the ids of the vertices in the enclosing plan. */ holes: string[][]; }; /** * API for creating Floor Stack buildings. * * You can either create simple buildings from a stack of floors. * Or you can create buildings from a stack of floors plans with internal * units. * * You can use this API together with the Forma.proposal.addElement * API to create a building and add it to a the current proposal. * * @example * // Create a building with 3 floors with a 2 meter setback * // Place it where the user clicks in the scene * const { urn } = await Forma.elements.floorStack.createFromFloors({ * floors: [ * { * polygon: [ [0, 0], [10, 0], [10, 10], [0, 10], [0, 0] ], * height: 3, * }, * { * polygon: [ [0, 0], [10, 0], [10, 10], [0, 10], [0, 0] ], * height: 2.6, * }, * { * polygon: [ [0, 0], [10, 0], [10, 8], [0, 8], [0, 0] ], * height: 2.6, * }, * ], * }) * const point = await Forma.designTool.getPoint() * if (!point) return * const transform = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, point.x, point.y, point.z, 1] * await Forma.proposal.addElement({ urn, transform }); * * @example * // Create a building with 3 floors with a 2 meter setback * // Place it where the user clicks in the scene * const { urn } = await Forma.elements.floorStack.createFromFloors({ * floors: [ * { planId: "planId-1", height: 3 }, * { planId: "planId-1", height: 2.6 }, * { planId: "planId-2", height: 2.6 }, * ], * plans: [ * { * id: "planId-1", * vertices: [ * { id: "v1", x: 0, y: 0 }, * { id: "v2", x: 10, y: 0 }, * { id: "v3", x: 10, y: 10 }, * { id: "v4", x: 0, y: 10 }, * ], * units: [{ * polygon: ["v1", "v2", "v3", "v4"], * program: "LIVING_UNIT", * functionId: "commercial", * holes: [], * }], * }, * { * id: "planId-2", * vertices: [ * { id: "v5", x: 0, y: 0 }, * { id: "v6", x: 10, y: 0 }, * { id: "v7", x: 10, y: 8 }, * { id: "v8", x: 0, y: 8 }, * ], * units: [{ * polygon: ["v5", "v6", "v7", "v8"], * program: "LIVING_UNIT", * functionId: "residential", * holes: [], * }], * }, * ], * }) * const point = await Forma.designTool.getPoint() * if (!point) return * const transform = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, point.x, point.y, point.z, 1] * await Forma.proposal.addElement({ urn, transform }); * * @remarks * Available via {@link auto.Forma | Forma}.{@link index.EmbeddedViewSdk.elements | elements}.{@link elements.ElementsApi.floorStack | floorStack}. */ export declare class FloorStackApi { #private; /** @hidden */ constructor(iframeMessenger: IframeMessenger); /** * Create a 2.5D building from a stack of floors. * * By 2.5D, we mean that the building only has vertical walls and flat roofs. * The floors are given from bottom to top. * * Requires edit access to the project. See {@link EmbeddedViewSdk.getCanEdit | getCanEdit} for more info. * * @returns URN of the created building element. */ createFromFloors(request: { /** The floors which define the building */ floors: Floor[]; /** The optional floor plans to define floors from */ plans?: Plan[]; }): Promise<{ urn: string; }>; /** * Create multiple 2.5D buildings from stacks of floors. * * By 2.5D, we mean that the building only has vertical walls and flat roofs. * The floors are given from bottom to top. * * Requires edit access to the project. See {@link EmbeddedViewSdk.getCanEdit | getCanEdit} for more info. * * @returns URNs of the created building elements. */ createFromFloorsBatch(request: { /** The floors which define the building */ floors: Floor[]; /** The optional floor plans to define floors from */ plans?: Plan[]; }[]): Promise<{ urns: string[]; }>; } /** * The Blobs API allows you to read blobs related to an element * * @remarks * Available via {@link auto.Forma | Forma}.{@link index.EmbeddedViewSdk.elements | elements}.{@link elements.ElementsApi.blobs | blobs}. */ export declare class BlobsApi { #private; /** @hidden */ constructor(iframeMessenger: IframeMessenger); /** * Retrieve a blob by its id. * * Blobs are binary data that can be used for various purposes. * A common use case is together with linked representations * * @example * ```typescript * const { element } = await Forma.elements.get({ * urn: "urn:adsk-forma-elements:terrain:pro_cnusxrl4s1:c418dafe-1963-4160-9df5-239a49eef10b:1716818829774", * }) * * if (element.representations?.volumeMesh?.type === "linked") { * const blobResponse = await Forma.elements.blobs.get({ * blobId: element.representations.volumeMesh.blobId, * }) * const arrayBuffer: ArrayBuffer = blobResponse.data * } * ``` * * @returns an object containing the ArrayBuffer of the blob as data */ get(request: { /** BlobId of the blob you want. For example found through a linked representation */ blobId: string; }): Promise<{ data: ArrayBuffer; }>; }