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).
389 lines (388 loc) • 14 kB
TypeScript
import type { IframeMessenger } from "../iframe-messenger.js";
export type Position = {
x: number;
y: number;
z: number;
};
export type Scale = {
x: number;
y: number;
};
export type Bbox = {
min: Position;
max: Position;
};
/**
* Represents a terrain pad (flat polygon) that modifies the terrain surface.
*
* @remarks
* Terrain pads are used to create flat areas on the terrain at specific elevations.
* They are commonly used for building foundations, roads, or other construction purposes.
* The pad modifies the terrain mesh within its defined polygon boundary, setting
* all terrain vertices within that area to the specified elevation.
*
* @example
* ```typescript
* // Example of a TerrainPad object returned by getPads()
* {
* id: "7ab85ec80b3e2",
* coordinates: [
* { x: 100, y: 200 },
* { x: 150, y: 200 },
* { x: 150, y: 250 },
* { x: 100, y: 250 }
* ],
* elevation: 45.5,
* slopeAngle: 30,
* slopePercentage: 57.74
* }
* ```
*/
export type TerrainPad = {
/**
* Unique identifier for the terrain pad. Can be an arbitrary string.
*/
id: string;
/**
* Array of 2D coordinates defining the polygon boundary of the pad.
* Coordinates are in the local coordinate system (meters).
* The polygon should be closed (first and last points should form a closed shape).
*/
coordinates: {
x: number;
y: number;
}[];
/**
* The elevation of the pad in meters above sea level.
* All terrain within the pad boundary will be set to this elevation.
*/
elevation: number;
/**
* Whether to apply a grade to the pad.
* If true, the pad will be graded to the specified slope angle or slope percentage.
* If false, the pad will not be graded.
*/
applySlope: boolean;
/**
* The slope angle in degrees for the transition zone around the pad boundary.
* This defines how steeply the terrain slopes from the surrounding terrain
* to the pad's elevation at its boundary.
*
* When modifying pads, you must specify the slope using either
* {@link TerrainPad.slopeAngle} (in degrees) or {@link TerrainPad.slopePercentage}.
* If both are specified, the slope percentage will be used.
*
* Must be greater than 0 and strictly lower than 90 degrees.
*
* @remarks
* - When undefined, no slope buffer is applied and the terrain transitions
* abruptly at the pad boundary.
* - A value of 45 degrees means the terrain rises/falls 1 meter vertically
* for every 1 meter of horizontal distance in the buffer zone.
* - Smaller angles create gentler slopes; larger angles create steeper slopes.
*
* @see {@link TerrainPad.slopePercentage} for the equivalent slope as a percentage.
*/
slopeAngle?: number;
/**
* The slope percentage for the transition zone around the pad boundary.
* This is an alternative representation of the slope, where 100% means
* the terrain rises/falls 1 meter vertically for every 1 meter of horizontal distance.
*
* When modifying pads, you must specify the slope using either
* {@link TerrainPad.slopeAngle} (in degrees) or {@link TerrainPad.slopePercentage}.
* If both are specified, the slope percentage will be used.
*
* Must be larger than 0.
*
* @remarks
* - When undefined, no slope buffer is applied and the terrain transitions
* abruptly at the pad boundary.
* - A value of 100 corresponds to a 45-degree slope angle.
* - A value of 50 corresponds to approximately a 26.57-degree slope angle.
* - This value is mathematically related to {@link TerrainPad.slopeAngle} by:
* `slopePercentage = tan(slopeAngle * π / 180) * 100`
*
* @see {@link TerrainPad.slopeAngle} for the equivalent slope in degrees.
*/
slopePercentage?: number;
};
/**
* Interact with the terrain in the 3D scene.
*
* @remarks
* Available via {@link auto.Forma | Forma}.{@link index.EmbeddedViewSdk.terrain | terrain}.
*/
export declare class TerrainApi {
#private;
groundTexture: GroundTextureApi;
/** @hidden */
constructor(iframeMessenger: IframeMessenger);
/**
* Fetch the bounding box for the terrain.
*
* @returns Axis-aligned bounding box for the terrain.
* More specifically, the minimum and maximum (x,y,z) values, in the local coordinate system.
*/
getBbox(): Promise<Bbox>;
/**
* Retrieves the elevation of the terrain (in meters above sea level) at a specific point within the scene.
*
* If the coordinates are outside the terrain mesh, it returns the minimum elevation in the terrain.
*/
getElevationAt(request: {
/** The X-coordinate of the point in the local coordinate system. */
x: number;
/** The Y-coordinate of the point in the local coordinate system. */
y: number;
}): Promise<number>;
/**
* Returns whether the terrain is internal.
*
* @remarks
* Internal terrain is managed fully within Forma Site Design.
* Non-internal terrain can potentially be coming from other cloud applications,
* including Revit Cloud Model and other Forma Connected Clients.
*
* Certain operations such as {@link TerrainApi.addPads | addPads},
* {@link TerrainApi.applyPads | applyPads}, and
* {@link ProposalApi.replaceTerrain | replaceTerrain} are only supported
* for internal terrains.
*/
isInternal(): Promise<boolean>;
/**
* Retrieves all terrain pads defined in the current terrain.
*
* @remarks
* Terrain pads are flat areas applied to the terrain surface.
*
* Each pad defines a polygon boundary at a specific elevation. The terrain mesh
* within the polygon is modified to match the pad's elevation. An optional slope
* angle defines how the terrain transitions from surrounding areas to the pad.
*
* @returns An array of {@link TerrainPad} objects representing all terrain pads.
* Returns an empty array if no pads are defined on the terrain.
*
* @example
* ```typescript
* // Retrieve all terrain pads
* const pads = await Forma.terrain.getPads();
*
* // Log information about each pad
* for (const pad of pads) {
* console.log(`Pad ID: ${pad.id}`);
* console.log(` Elevation: ${pad.elevation}m`);
* console.log(` Vertices: ${pad.coordinates.length}`);
* if (pad.slopeAngle !== undefined) {
* console.log(` Slope angle: ${pad.slopeAngle}°`);
* }
* }
* ```
*/
getPads(): Promise<TerrainPad[]>;
/**
* Adds new terrain pads to the existing pads on the terrain.
*
* @remarks
* This method appends the provided pads to the current set of terrain pads
* without removing or modifying existing ones. Use this when you want to
* incrementally add new flat areas to the terrain while preserving existing pads.
*
* This method is only supported when the terrain is internal.
* Use {@link TerrainApi.isInternal | isInternal} to check whether the terrain is internal.
*
* Each pad must specify its slope using either `slopeAngle` (in degrees) or
* `slopePercentage`, but not both.
*
* @param pads - Array of terrain pads to add.
*
* @example
* ```typescript
* // Add multiple pads with different slope specifications
* await Forma.terrain.addPads([
* {
* id: "7ab85ec80b3e2",
* coordinates: [
* { x: 0, y: 0 },
* { x: 100, y: 0 },
* { x: 100, y: 100 },
* { x: 0, y: 100 }
* ],
* elevation: 50,
* applySlope: true,
* slopeAngle: 30 // Using degrees
* },
* {
* id: "70234fcf791b2",
* coordinates: [
* { x: 200, y: 0 },
* { x: 300, y: 0 },
* { x: 300, y: 100 },
* { x: 200, y: 100 }
* ],
* elevation: 45,
* applySlope: true,
* slopePercentage: 50 // Using percentage
* },
* {
* id: "70234fcf791b3",
* coordinates: [
* { x: 200, y: 0 },
* { x: 300, y: 0 },
* { x: 300, y: 100 },
* { x: 200, y: 100 }
* ],
* elevation: 45,
* applySlope: false // No slope applied; abrupt pad
* }
* ]);
* ```
*
* @see {@link TerrainApi.applyPads} to replace all existing pads.
* @see {@link TerrainApi.getPads} to retrieve current pads.
*/
addPads(pads: TerrainPad[]): Promise<void>;
/**
* Replaces all existing terrain pads with the provided array of pads.
*
* @remarks
* This method unconditionally sets the terrain pads to the provided array,
* removing any existing pads that are not included in the new array.
* Use this when you want complete control over the terrain pads, or when
* you need to remove pads.
*
* This method is only supported when the terrain is internal.
* Use {@link TerrainApi.isInternal | isInternal} to check whether the terrain is internal.
*
* To remove all pads, call this method with an empty array.
*
* @param pads - Array of terrain pads to set. Pass an empty array to remove all pads.
*
* @example
* ```typescript
* // Replace all pads with a new set
* await Forma.terrain.applyPads([
* {
* id: "7ab85ec80b3e2",
* coordinates: [
* { x: 0, y: 0 },
* { x: 100, y: 0 },
* { x: 100, y: 100 },
* { x: 0, y: 100 }
* ],
* elevation: 50,
* applySlope: true,
* slopeAngle: 30
* }
* ]);
* ```
*
* @example
* ```typescript
* // Remove all terrain pads
* await Forma.terrain.applyPads([]);
* ```
*
* @see {@link TerrainApi.addPads} to add pads without removing existing ones.
* @see {@link TerrainApi.getPads} to retrieve current pads.
*/
applyPads(pads: TerrainPad[]): Promise<void>;
}
/**
* Manage ground textures applied to the terrain object in the 3D scene.
*
* @remarks
* Available via {@link auto.Forma | Forma}.{@link index.EmbeddedViewSdk.terrain | terrain}.{@link terrain.TerrainApi.groundTexture | groundTexture}.
*/
export declare class GroundTextureApi {
#private;
/** @hidden */
constructor(iframeMessenger: IframeMessenger);
/**
* Add a ground texture to the terrain.
*
* @example
* // Create canvas
* const canvas = document.createElement("canvas");
* canvas.width = 100;
* canvas.height = 100;
*
* // Fill canvas with blue color
* const ctx = canvas.getContext("2d");
* if (ctx) {
* ctx.fillStyle = "blue";
* ctx.fillRect(0, 0, 100, 100);
*
* // Add canvas as ground texture to position (0, 0) in the local coordinate system.
* // The texture will cover a 100x100 meter square area on the terrain,
* // with lower left corner in (x: -50, y: -50) and upper right corner in (x: 50, y: 50).
* await Forma.terrain.groundTexture.add({
* name: "myGroundTexture",
* canvas,
* position: { x: 0, y: 0, z: 1 },
* scale: { x: 1, y: 1 },
* });
* }
*/
add(request: {
/** The name of the texture to add. */
name: string;
/** The canvas to use as texture data. */
canvas: HTMLCanvasElement;
/** x and y position denotes where to place the center of the canvas. z gives the order of the ground texture and overlapping textures with a larger z position will cover those with a smaller one. */
position: Position;
/** The number of meters each pixel in the canvas represents. Defaults to 1 meter. */
scale?: Scale | undefined;
}): Promise<void>;
/**
* Update the texture data for an existing ground texture object.
*
* @example
* // Create a new canvas filled with red and update the ground texture with this new texture
* const newCanvas = document.createElement("newCanvas");
* newCanvas.width = 100;
* newCanvas.height = 100;
* const ctx = newCanvas.getContext("2d");
* if (ctx) {
* ctx.fillStyle = "red";
* ctx.fillRect(0, 0, 100, 100);
* await Forma.terrain.groundTexture.updateTextureData({
* name: "myGroundTexture",
* canvas: newCanvas,
* });
* }
*/
updateTextureData(request: {
/** The name of the texture to update. */
name: string;
/** The canvas to use as updated texture data. */
canvas: HTMLCanvasElement;
}): Promise<void>;
/**
* Update the placement of an existing ground texture object.
*
* @example
* // Move "myGroundTexture" to (100, 100) in the local coordinate system.
* await Forma.terrain.groundTexture.updatePosition({
* name: "myGroundTexture",
* position: { x: 100, y: 100, z: 1 }
* })
*/
updatePosition(request: {
/** The name of the texture to move. */
name: string;
/** The position to move the ground texture to. x and y position denotes where to place the center of the canvas. z gives the order of the ground texture and overlapping textures with a larger z position will cover those with a smaller one. */
position: Position;
}): Promise<void>;
/**
* Remove an existing ground texture object.
*
* @example
* // Remove "myGroundTexture".
* await Forma.terrain.groundTexture.remove({ name: "myGroundTexture" })
*/
remove(request: {
/** The name of the texture to remove. */
name: string;
}): Promise<void>;
}