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
TypeScript
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;
}>;
}