Interface InfiniteEngineInterface

The InfiniteEngineInterface interface is used to render the content of the DMU.

The usage is very basic :

  • create an InfiniteEngineInterface connected to a MetadataManagerInterface.
  • connect it to a DOMElement.
  • change the way geometric instances are rendered.

WARNING : There is no automatic conversion of the content of FilterSolverInterface to the 3D engine. It is the role of the web application to show/hide/ghost geometries depending on the application needs.

Initialization.

The InfiniteEngineInterface is initialized from a MetadataManagerInterface by an InfiniteFactory.
The InfiniteEngineInterface takes advantage of the MetadataManagerInterface connected to a DataSessionInterface. The use of the InfiniteEngineInterface is only relevant when a DataSessionInterface is connected to a 3djuump infinite build.

/** 
* Sample to illustrate the initialization of an InfiniteEngineInterface.
*/
import { InfiniteEngineInterface, InfiniteFactory, InfiniteEngineInterfaceSignal, MetadataManagerInterface, tListenerCallback } from 'generated/documentation/appinfiniteapi';

// created previously
let lMetadataManager : MetadataManagerInterface;
// the callback when a pick request is completed
let onPicking : tListenerCallback;

// create an infinite engine
const lInfiniteEngine : InfiniteEngineInterface = InfiniteFactory.CreateInfiniteEngine(lMetadataManager);
// get the html element that will host the 3d rendering
const lView3D: HTMLElement = <HTMLElement>document.getElementById('rendering');
// bind the rendering to the given div
lInfiniteEngine.setView(lView3D);
// and use anti-aliasing => smoother
lInfiniteEngine.enableAntiAliasing(true);
// register the callback for pick result
lInfiniteEngine.addEventListener(InfiniteEngineInterfaceSignal.Picked, onPicking);

Creation of an InfiniteEngineInterface.

Rendering.

The InfiniteEngineInterface display is governed by a resource controller. Indeed, the display is based on some low definition rendering of the DMU, and HD geometric data rendered on top of it. The amount of acceptable data is governed by the PerformanceInterface that provides a way to set the budgets. Such budgets rely heavily on the hardware of the end-user. It is recommended to allow the end-user to manipulate such budgets.
The low definition version of the DMU is composed of a static version (not configurable), and a dynamic one, whom triangle number can be configured.

/** 
* Sample to illustrate setting some performance settings of the InfiniteEngineInterface
* by using the PerformanceInterface.
*/
import { MetadataManagerInterface, PerformanceInterface } from 'generated/documentation/appinfiniteapi';

// created previously
let lMetadataManager : MetadataManagerInterface;
// get the performance interface
const lPerformanceInfos : PerformanceInterface = lMetadataManager.getPerformanceInfos();

// reset the number of triangles to display in the dynamic low definition DMU
lPerformanceInfos.setMaxNbDynamicLowDefTrianglesDisplayed(lPerformanceInfos.GetMaxDynamicLowDefTrianglesDefault());
// reset the number of total triangles to be displayed
lPerformanceInfos.setMaxNbTrianglesDisplayed(lPerformanceInfos.GetMaxTrianglesDefault());
// reset the VRAM (RAM on the GPU) amount to be used
lPerformanceInfos.setMaxRenderingMemory(lPerformanceInfos.GetMaxRenderingMemoryDefault());
// reset the RAM to use when downloading data (if geometries are too big, less geometries will be downloaded at the same time)
lPerformanceInfos.setMaxWorkingMemory(lPerformanceInfos.GetMaxWorkingMemoryDefault());

The state of the resource controller (ok, out of budget, running) is retrieved from [getResourceLoadingState](InfiniteEngineInterface.html#getResourceLoadingState) and the [LoadingStates](../enums/LoadingStates.html) enumeration.
 /** 
* Sample to illustrate getting the loading state (updating, ok, out of budget) of the InfiniteEngineInterface.
*/
import { InfiniteEngineInterface, LoadingStates } from 'generated/documentation/appinfiniteapi';

// created previously
let lInfiniteEngine : InfiniteEngineInterface;
// gets the loading state of the resource controller when the DMU has been loaded
const lLoadingState : LoadingStates = lInfiniteEngine.getResourceLoadingState();
// and output its value
console.log('current loading state ' + lLoadingState)

An optional [InfiniteCacheInterface](InfiniteCacheInterface.html) may be included in the [DataSessionInterface](DataSessionInterface.html) upon creation to speed up the retrieving of HD geometric data.

Geometric instances are accessed through their geometric instance ids, and each geometric instance may be :

  • Hidden : object is not displayed.
  • Selected : objet is rendered in a pulsing orange.
  • Ghosted : the object is rendered semi transparent in a light blue color.
  • Ignore cut plane : object cannot be hidden by a cut plane.

Such a state is a bit field, and bits can be changed in a batch for multiple geometric instances.
Use VisualStates with updateGeometricState, getGeometricState and updateGeometricStateForAll functions to change the way geometries are rendered. The visibility is coded on a 8 bits unsigned number.

In the following examples, x represent an irrelevant bit :

/** 
* Sample to illustrate how to change the visibility of a set of `geometric instances`.
*/
import { InfiniteEngineInterface, VisualStates } from 'generated/documentation/appinfiniteapi';

// created previously
let lInfiniteEngine : InfiniteEngineInterface;

// 8 bits for visibility
// sets all instances visible and not ghosted (do not care about "x" values)
// Mask => xxxx 1101
//
// not ghosted => xxxx x0xx
// not hidden (visible) => xxxx 0xx0
// we want to set => xxxx 00x0
// we can use 0 for values !!!!
lInfiniteEngine.updateGeometricStateForAll(VisualStates.S_Ghost | VisualStates.S_Hidden, 0);

// sets 2 instances hidden, but clear the ghost for them, and clear selection
// Mask => xxxx 1111
//
// not ghosted => xxxx x0xx
// hidden => xxxx 1xx1
// not selected => xxxx xx0x
// we want to set => xxxx 1001
// we can use VisualStates.S_Hidden for values !!!!
const lCurrentGeometries : Uint32Array = new Uint32Array(2);
lCurrentGeometries[0] = 57;
lCurrentGeometries[1] = 64;
lInfiniteEngine.updateGeometricState(lCurrentGeometries, VisualStates.S_Ghost | VisualStates.S_Hidden | VisualStates.S_Selected, VisualStates.S_Hidden);

The color of each `geometric instance` can be modified with the use of the [MaterialManagerInterface](MaterialManagerInterface.html) accessed through [getMaterialManager](InfiniteEngineInterface.html#getMaterialManager). The [MaterialManagerInterface](MaterialManagerInterface.html) stores the properties of the default and user defined materials.
It is recommended to reuse (if possible) user defined materials since only a limited number of materials can be created. Materials are accessed by their id (a positive number). Colors are defined as a [Vector3](../classes/Vector3.html), `x` being the red component, `y` being the green component, `z` the blue component in the `[0:1]` range (e.g `[1,0,0]` is pure red, `[0,1,0]` is pure green, ...).
/** 
* Sample to illustrate the change of colors of `geometric instance` (MaterialManagerInterface).
*/
import { InfiniteEngineInterface, MaterialManagerInterface, Vector3 } from 'generated/documentation/appinfiniteapi';

// created previously
let lInfiniteEngine : InfiniteEngineInterface;
// the `geometric instance id` to check
let lGeometricInstanceId : number;
// get the material manager
const lMaterialManager : MaterialManagerInterface = lInfiniteEngine.getMaterialManager();

// warning, in case of multi materials, multiple materials may be retrieved
const lNbMaterials : number = lMaterialManager.getOriginalNbMaterialsOfInstance(lGeometricInstanceId);
const lOriginalMaterials : number[] = [];

if ((!lMaterialManager.getOriginalMaterialsOfInstance(lGeometricInstanceId, lOriginalMaterials)) || (lOriginalMaterials.length === 0))
{
console.log('Error while fetching original materials');
}
console.assert(lNbMaterials === (lOriginalMaterials.length));

// get the diffuse color of the given `geometric instance`
const lOriginalColor : Vector3 = new Vector3();
if (!lMaterialManager.getMaterialDiffuse(lOriginalMaterials[0], lOriginalColor))
{
console.log('Error while fetching original material color')
}

// colors are expressed as Vector3 red,green,blue (in this order), in the range [0:1]
//
const lGreenColor : Vector3 = new Vector3(0, 1, 0);
const lRedColor : Vector3 = new Vector3(1, 0, 0);
const lBlueColor : Vector3 = new Vector3(0, 0, 1);
const lWhiteColor : Vector3 = new Vector3(1, 1, 1);

// create an array of colors to cycle through
const lColors : Vector3 [] = [lGreenColor, lRedColor, lBlueColor, lWhiteColor];
// where are we in the array ?
let lCurrentColorOffset : number = 0;

// create a custom material, but instead of creating multiple materials, use one and
// modify it
const lCustomMaterialId : number = lMaterialManager.createNewMaterial(lRedColor);

// callback to be called on mouse down
const onChangeMaterial = () : void =>
{
// should we set a color or restore it ?
if (lCurrentColorOffset < lColors.length)
{
// modify the custom material
lMaterialManager.modifyMaterial(lCustomMaterialId, lColors[lCurrentColorOffset]);
if (lMaterialManager.getMaterialOfInstance(lGeometricInstanceId) !== lCustomMaterialId)
{
// and change the current material if relevant
lMaterialManager.changeMaterialOfInstance(lGeometricInstanceId, lCustomMaterialId);
}
// next color for next time
++lCurrentColorOffset;
}
else
{
// we should restore the material for the element
if (lMaterialManager.getMaterialOfInstance(lGeometricInstanceId) === lCustomMaterialId)
{
// but only if relevant
lMaterialManager.restoreOriginalMaterialOfInstance(lGeometricInstanceId);
}
// go back to the start of tests
lCurrentColorOffset = 0;
}
}

// when should we change the colors of the given `geometric instance` ?
// => mouse down
document.addEventListener('mousedown', onChangeMaterial);

Changing materials.

Picking.

The "picking" is the action to get the visible item under a specific position in the 3d view. The picking is dependant on the state of the resource controller, i.e. querying multiple picks at the same location without changing the camera position may result in different results, depending on the loaded data.

The picking is asynchronous, meaning a Picked signal is triggered when the result is available, with an attachment of the PickingAttachment type, which stores for each picked object :

  • its id (geometric instance id/point id/line id/box id).
  • its closest 3D position (a virtual ray is casted on the scene for each picking position, the resulting point is the closest point of the set of the intersection of these rays and the object).
  • the number of times this object is intersected (minimum one).
  • the picking request id (please see getLastPickingRequestId).

Multiple pick requests can be queued, calling multiple times pickAt without waiting for the result will trigger multiple Picked events, they can be distinguished with their picking request ids (getLastPickingRequestId and pickingRequestId).
Geometric instances, lines, boxes, and points are queried at the same time on a single pick request (see PrimitiveManagerLineInterface, PrimitiveManagerBoxInterface, PrimitiveManagerPointInterface). The pickRay and projectToScreen functions may be used with the pick functions to make some more 3D calculations. You may pick a single point (pickAt), a rectangular area (pickRect), or the 3D that intersects a 3D ray. There are some limitations to the 3D ray pick :

  • The ray must be oriented toward the direction of the camera (the dot vector between the direction of the camera and the direction of the ray must be positive).
  • Only 3D elements actually rendered may be picked (no ray pick outside the frustum).
  • The pick ray algorithm rely on the projection of the surfaces to the near plane, objects that are less than 2 pixels wide and 2 pixels high cannot be picked.

The picking system works with client coordinates :

  • x between 0 and clientWidth-1.
  • y between 0 and clientHeight-1.

The actual picked point follows the following convention : picking convention
The PrimitiveManagerRubberBandInterface can be used to display a rectangular area on top of the 3d rendering element.

/** 
* Sample to illustrate the handling of a mouse pick in an InfiniteEngineInterface.
*/
import { InfiniteEngineInterface, InfiniteFactory, MetadataManagerInterface, PickingAttachment, PickingAttachmentItem, Vector3, VisualStates, InfiniteEngineInterfaceSignal, Rectangle, InfiniteEvent, PrimitiveManagerInterface } from 'generated/documentation/appinfiniteapi';

// created previously
let lMetadataManager : MetadataManagerInterface;
// the div to render to
let lView3D: HTMLElement;

// create an 3D engine
const lInfiniteEngine: InfiniteEngineInterface = InfiniteFactory.CreateInfiniteEngine(lMetadataManager);

// What to do on pick ?
let onButtonClicked : (pEvent) => void = undefined;

// What to do on pick ?
let onPicking : (pEvent : InfiniteEvent, _pCallbackData) => void = undefined;

// We pick a rectangle if big enough, else only a point
let pickAtImpl : () => void = undefined;

// bind the 3D rendering to the div
lInfiniteEngine.setView(lView3D);

// ####################################################################################################################################
// ############################################ PICKING ###############################################################################
// ####################################################################################################################################
// Used to copy the relevant portion of a MouseEvent
// position, previous buttons, current button and type
// store also if we started showing the rubber band
interface EventPos
{
x : number;
y : number;
buttons : number;
button : number;
type : string;
// is the rubber band initialized, i.e. have we begun to draw a rectangle ?
rubberInit : boolean;
}
// store the last click to know the extent of the rectangle to pick, and after pick request
// to know the properties of the pick request
// we store a copy of the MouseEvent
const lLastClickEvent: EventPos = {
x: 0,
y: 0,
buttons: 0,
button: 0,
type: '',
rubberInit: false,
};

// What to do on pick ?
onPicking = (pEvent : InfiniteEvent, _pCallbackData) : void =>
{
const lAttachment: PickingAttachment = <PickingAttachment>pEvent.attachments;
// care only about 3d geometries (no line, point, box)
const l3dAttachment: PickingAttachmentItem[] | undefined = lAttachment.geometric;

let lFirstGeometricId: number = 0;
let l3dPosition: Vector3 | undefined = undefined;
if (l3dAttachment !== undefined && l3dAttachment.length > 0)
{
lFirstGeometricId = l3dAttachment[0].instanceId;
l3dPosition = l3dAttachment[0].position;
}

// Mid button click => set Center Of Interest (COI)
if (lLastClickEvent.button === 1) {
if (!l3dPosition) return;
// set the center coi
lInfiniteEngine.getCameraManager().lookAt(l3dPosition);
return;
}

// no left button click => do nothing
if (lLastClickEvent.button !== 0)
{
return;
}
// if double click
if (lLastClickEvent.type === 'dblclick')
{
// fit to geometry
lInfiniteEngine.getCameraManager().fitGeometry(lFirstGeometricId);
return;
}
// clear selected state on pick
let lWasSelected: boolean = false;
if (lFirstGeometricId !== 0)
{
const lGeomState = lInfiniteEngine.getGeometricState(lFirstGeometricId);
lWasSelected = ((lGeomState & VisualStates.S_Selected) !== 0);
}
// if multiple selections => do not change the selected state of a single geometry
// but select all the relevant 3D data instead
if (l3dAttachment && l3dAttachment.length > 1)
{
lWasSelected = false;
}
// unselect everyone
lInfiniteEngine.updateGeometricStateForAll(VisualStates.S_Selected, ~VisualStates.S_Selected);
// and begin
if (lFirstGeometricId !== 0 && !lWasSelected && l3dAttachment)
{
// update visual state of selected items
const lIds = new Uint32Array(l3dAttachment.length);
for (let i = 0; i < l3dAttachment.length; ++i) {
lIds[i] = l3dAttachment[i].instanceId;
}
lInfiniteEngine.updateGeometricState(lIds, VisualStates.S_Selected, VisualStates.S_Selected);
}
};

// and bind the callback on pick result
lInfiniteEngine.addEventListener(InfiniteEngineInterfaceSignal.Picked, onPicking);

// the rectangle to pick (if relevant)
const lRubberBand: Rectangle = new Rectangle();

// We pick a rectangle if big enough, else only a point
pickAtImpl = (): void =>
{
// single pick if small rectangle
if (((lRubberBand.width <= 3) && (lRubberBand.height <= 3)) || (lRubberBand.width === 0) || (lRubberBand.height === 0))
{
// pick the last point
lInfiniteEngine.pickAt(lLastClickEvent.x, lLastClickEvent.y);
}
else
{
// pick an area
lInfiniteEngine.pickRect(lRubberBand);
}
// and clear the rectangle in all the cases
lRubberBand.clear();
}

onButtonClicked = (event) : void =>
{
lLastClickEvent.x = event.offsetX;
lLastClickEvent.y = event.offsetY;
lLastClickEvent.button = event.button;
lLastClickEvent.buttons = event.buttons;
lLastClickEvent.type = event.type;
lLastClickEvent.rubberInit = false;

if (lLastClickEvent.buttons === 0)
{
// make a pick
pickAtImpl();
}
}
// on left click => pick
lView3D.addEventListener('click', onButtonClicked);

const onMouseDown = (event) : void =>
{
// store the pick start
lLastClickEvent.x = event.offsetX;
lLastClickEvent.y = event.offsetY;
lLastClickEvent.button = event.button;
lLastClickEvent.buttons = event.buttons;
lLastClickEvent.type = event.type;
// no rubber
lLastClickEvent.rubberInit = false;
}
// store the position to the first pick pos
lView3D.addEventListener('mousedown', onMouseDown);

// when we release the mouse button, make a pick only on middle mouse if close to start pos
// and hide the rubber band
const onMouseUp = (event) : void =>
{
// middle click
if (lLastClickEvent.button === 1 && event.button === 1)
{
if (!lLastClickEvent.rubberInit) {
// if no rectangle => set COI
lLastClickEvent.x = event.offsetX;
lLastClickEvent.y = event.offsetY;
lLastClickEvent.button = event.button;
lLastClickEvent.buttons = event.buttons;
lLastClickEvent.type = event.type;
lLastClickEvent.rubberInit = false;
pickAtImpl();
}
}
const lPrimitiveManager : PrimitiveManagerInterface = lInfiniteEngine.getPrimitiveManager();
lPrimitiveManager.getRubberBandManager().setRubberBandVisible(false);
lLastClickEvent.x = event.offsetX;
lLastClickEvent.y = event.offsetY;
lLastClickEvent.button = event.button;
lLastClickEvent.buttons = event.buttons;
lLastClickEvent.type = event.type;
lLastClickEvent.rubberInit = false;
}

lView3D.addEventListener('mouseup', onMouseUp);

// we we move the mouse, display the rubber band
const onMouseMove = (event) : void =>
{
if (lLastClickEvent.rubberInit || (Math.abs(lLastClickEvent.x - event.offsetX) > 3 || Math.abs(lLastClickEvent.y - event.offsetY) > 3))
{
lRubberBand.x = Math.min(lLastClickEvent.x, event.offsetX);
lRubberBand.y = Math.min(lLastClickEvent.y, event.offsetY);
lRubberBand.width = Math.abs(lLastClickEvent.x - event.offsetX);
lRubberBand.height = Math.abs(lLastClickEvent.y - event.offsetY);
lLastClickEvent.rubberInit = true;
}
if ((lLastClickEvent.buttons === 1) && (event.buttons === 1) && lLastClickEvent.rubberInit)
{
// show/update the rubber band
const lPrimitiveManager: PrimitiveManagerInterface = lInfiniteEngine.getPrimitiveManager();
lPrimitiveManager.getRubberBandManager().setRubberBandRectangle(lRubberBand);
lPrimitiveManager.getRubberBandManager().setRubberBandVisible(true);
}
}
lView3D.addEventListener('mousemove', onMouseMove);

or with async calls :
/** 
* Sample to illustrate the handling of an asynchronous mouse pick in an InfiniteEngineInterface.
*/
import {
InfiniteEngineInterface, InfiniteFactory, MetadataManagerInterface, PickingAttachment, PickingAttachmentItem, Vector3, VisualStates, AsyncPickingResult,
Rectangle, AsyncResultReason, PrimitiveManagerInterface,
} from 'generated/documentation/appinfiniteapi';

// created previously
let lMetadataManager : MetadataManagerInterface;
// the div to render to
let lView3D: HTMLElement;

// create an 3D engine
const lInfiniteEngine: InfiniteEngineInterface = InfiniteFactory.CreateInfiniteEngine(lMetadataManager);

// What to do on pick ?
let onButtonClicked : (pEvent) => void = undefined;

// We pick a rectangle if big enough, else only a point
let pickAtImpl : () => void = undefined;

// bind the 3D rendering to the div
lInfiniteEngine.setView(lView3D);

// ####################################################################################################################################
// ############################################ PICKING ###############################################################################
// ####################################################################################################################################
// Used to copy the relevant portion of a MouseEvent
// position, previous buttons, current button and type
// store also if we started showing the rubber band
interface EventPos
{
x : number;
y : number;
buttons : number;
button : number;
type : string;
// is the rubber band initialized, i.e. have we begun to draw a rectangle ?
rubberInit : boolean;
}
// store the last click to know the extent of the rectangle to pick, and after pick request
// to know the properties of the pick request
// we store a copy of the MouseEvent
const lLastClickEvent: EventPos = {
x: 0,
y: 0,
buttons: 0,
button: 0,
type: '',
rubberInit: false,
};

// What to do on pick ?
const onPicking = (pAttachment: PickingAttachment) : void =>
{
// care only about 3d geometries (no line, point, box)
const l3dAttachment: PickingAttachmentItem[] | undefined = pAttachment.geometric;

let lFirstGeometricId: number = 0;
let l3dPosition: Vector3 | undefined = undefined;
if (l3dAttachment !== undefined && l3dAttachment.length > 0)
{
lFirstGeometricId = l3dAttachment[0].instanceId;
l3dPosition = l3dAttachment[0].position;
}

// Mid button click => set Center Of Interest (COI)
if (lLastClickEvent.button === 1) {
if (!l3dPosition) return;
// set the center coi
lInfiniteEngine.getCameraManager().lookAt(l3dPosition);
return;
}

// no left button click => do nothing
if (lLastClickEvent.button !== 0)
{
return;
}
// if double click
if (lLastClickEvent.type === 'dblclick')
{
// fit to geometry
lInfiniteEngine.getCameraManager().fitGeometry(lFirstGeometricId);
return;
}
// clear selected state on pick
let lWasSelected: boolean = false;
if (lFirstGeometricId !== 0)
{
const lGeomState = lInfiniteEngine.getGeometricState(lFirstGeometricId);
lWasSelected = ((lGeomState & VisualStates.S_Selected) !== 0);
}
// if multiple selections => do not change the selected state of a single geometry
// but select all the relevant 3D data instead
if (l3dAttachment && l3dAttachment.length > 1)
{
lWasSelected = false;
}
// unselect everyone
lInfiniteEngine.updateGeometricStateForAll(VisualStates.S_Selected, ~VisualStates.S_Selected);
// and begin
if (lFirstGeometricId !== 0 && !lWasSelected && l3dAttachment)
{
// update visual state of selected items
const lIds = new Uint32Array(l3dAttachment.length);
for (let i = 0; i < l3dAttachment.length; ++i) {
lIds[i] = l3dAttachment[i].instanceId;
}
lInfiniteEngine.updateGeometricState(lIds, VisualStates.S_Selected, VisualStates.S_Selected);
}
};

// the rectangle to pick (if relevant)
const lRubberBand: Rectangle = new Rectangle();

// We pick a rectangle if big enough, else only a point
pickAtImpl = async () : Promise<any> =>
{
let lPickingResult : AsyncPickingResult;
// single pick if small rectangle
if (((lRubberBand.width <= 3) && (lRubberBand.height <= 3)) || (lRubberBand.width === 0) || (lRubberBand.height === 0))
{
// pick the last point
lPickingResult = await lInfiniteEngine.asyncPickAt(lLastClickEvent.x, lLastClickEvent.y);
}
else
{
// pick an area
lPickingResult = await lInfiniteEngine.asyncPickRect(lRubberBand);
}
// and clear the rectangle in all the cases
lRubberBand.clear();
if (lPickingResult.reason !== AsyncResultReason.ARR_Success || lPickingResult.value === undefined)
{
return;
}
onPicking(lPickingResult.value);
}

onButtonClicked = (event) : void =>
{
lLastClickEvent.x = event.offsetX;
lLastClickEvent.y = event.offsetY;
lLastClickEvent.button = event.button;
lLastClickEvent.buttons = event.buttons;
lLastClickEvent.type = event.type;
lLastClickEvent.rubberInit = false;

if (lLastClickEvent.buttons === 0)
{
// make a pick
pickAtImpl();
}
}
// on left click => pick
lView3D.addEventListener('click', onButtonClicked);

const onMouseDown = (event) : void =>
{
// store the pick start
lLastClickEvent.x = event.offsetX;
lLastClickEvent.y = event.offsetY;
lLastClickEvent.button = event.button;
lLastClickEvent.buttons = event.buttons;
lLastClickEvent.type = event.type;
// no rubber
lLastClickEvent.rubberInit = false;
}
// store the position to the first pick pos
lView3D.addEventListener('mousedown', onMouseDown);

// when we release the mouse button, make a pick only on middle mouse if close to start pos
// and hide the rubber band
const onMouseUp = (event) : void =>
{
// middle click
if (lLastClickEvent.button === 1 && event.button === 1)
{
if (!lLastClickEvent.rubberInit) {
// if no rectangle => set COI
lLastClickEvent.x = event.offsetX;
lLastClickEvent.y = event.offsetY;
lLastClickEvent.button = event.button;
lLastClickEvent.buttons = event.buttons;
lLastClickEvent.type = event.type;
lLastClickEvent.rubberInit = false;
pickAtImpl();
}
}
const lPrimitiveManager : PrimitiveManagerInterface = lInfiniteEngine.getPrimitiveManager();
lPrimitiveManager.getRubberBandManager().setRubberBandVisible(false);
lLastClickEvent.x = event.offsetX;
lLastClickEvent.y = event.offsetY;
lLastClickEvent.button = event.button;
lLastClickEvent.buttons = event.buttons;
lLastClickEvent.type = event.type;
lLastClickEvent.rubberInit = false;
}

lView3D.addEventListener('mouseup', onMouseUp);

// we we move the mouse, display the rubber band
const onMouseMove = (event) : void =>
{
if (lLastClickEvent.rubberInit || (Math.abs(lLastClickEvent.x - event.offsetX) > 3 || Math.abs(lLastClickEvent.y - event.offsetY) > 3))
{
lRubberBand.x = Math.min(lLastClickEvent.x, event.offsetX);
lRubberBand.y = Math.min(lLastClickEvent.y, event.offsetY);
lRubberBand.width = Math.abs(lLastClickEvent.x - event.offsetX);
lRubberBand.height = Math.abs(lLastClickEvent.y - event.offsetY);
lLastClickEvent.rubberInit = true;
}
if ((lLastClickEvent.buttons === 1) && (event.buttons === 1) && lLastClickEvent.rubberInit)
{
// show/update the rubber band
const lPrimitiveManager: PrimitiveManagerInterface = lInfiniteEngine.getPrimitiveManager();
lPrimitiveManager.getRubberBandManager().setRubberBandRectangle(lRubberBand);
lPrimitiveManager.getRubberBandManager().setRubberBandVisible(true);
}
}
lView3D.addEventListener('mousemove', onMouseMove);

Please make sure the destination browser supports promises before using async calls.

Screenshots.

Screenshots can be performed with the screenshot call. The screenshot procedure is asynchronous, and the ScreenshotReady event is fired when the screenshot is ready. The screenshot call returns an id, and this is must match the attachment of the ScreenshotReady event which is an InfiniteImageInterface (screenshotid). An empty string means the screenshot procedure has failed (a missing setView call probably). An empty width or height means the image is invalid. Multiple screenshot calls can be executed concurrently.

You may want to call setFixedResolution to get a screenshot of this size.

/** 
* Sample to illustrate the screenshot procedure of the InfiniteEngineInterface.
*/
import {
InfiniteEngineInterface, LoadingStates, Vector3, InfiniteEngineLoadingStateAttachment,
InfiniteEngineInterfaceSignal, InfiniteEvent, InfiniteImageInterface, ScreenshotType
} from 'generated/documentation/appinfiniteapi';

// We try to make a screenshot when all data is loaded

// the div to render the 3D display
let lView3D: HTMLElement;

// created previously, should receive the image data to be displayed to the user (or ask for a download maybe ?)
let lImageData : HTMLImageElement;

// created previously the position of the camera for the screenshot
let lCameraLocation : Vector3;

// created previously the camera center of interest
let lCenterOfInterest : Vector3;

// created previously the 3D engine
let lInfiniteEngine: InfiniteEngineInterface;

let lScreenshotId : string = '';
// What to do when screenshot is ready ?
let onScreenshotReady : (pEvent : InfiniteEvent, _pCallbackData) => void = undefined;

// What to do when all data is loaded ?
let onDataStateChanged : (pEvent : InfiniteEvent, _pCallbackData) => void = undefined;

// bind the 3D rendering to the div (should have been done earlier :) )
lInfiniteEngine.setView(lView3D);

// we will make screenshot of 1024x1024
lInfiniteEngine.setFixedResolution(1024, 1024, 1);

lInfiniteEngine.addEventListener(InfiniteEngineInterfaceSignal.LoadingStateChanged, onDataStateChanged);
lInfiniteEngine.addEventListener(InfiniteEngineInterfaceSignal.ScreenshotReady, onScreenshotReady);

// go to the expected position / location
lInfiniteEngine.getCameraManager().setCameraLocation(lCameraLocation);
lInfiniteEngine.getCameraManager().lookAt(lCenterOfInterest, 0);

// ####################################################################################################################################
// ############################################ Screenshot ############################################################################
// ####################################################################################################################################

// What to do when state changes ? We wait till everything is loaded and then make a screenshot
onDataStateChanged = (pEvent : InfiniteEvent, _pCallbackData) : void =>
{
// check the attachment
const lStateAttachment : InfiniteEngineLoadingStateAttachment = pEvent.attachments;

// some check, but useless, only for illustration purpose
console.assert(lStateAttachment.newLoadingState === lInfiniteEngine.getResourceLoadingState());

switch (lStateAttachment.newLoadingState)
{
case LoadingStates.S_Loading:
// do nothing if we are still loading
return;
case LoadingStates.S_OutOfBudget:
// some fancy message
console.log('Taking a screenshot without everything loaded');
// but we still make a screenshot :)
break;
default:
break;
}
// make a screenshot request in jpeg with 95% quality, data will be base64 encoded
lScreenshotId = lInfiniteEngine.screenshot(ScreenshotType.ST_Color, true, 'image/jpeg', 0.95);
if (lScreenshotId.length === 0)
{
// for some reason, this failed
console.log('Screenshot request failed');
}
}

// what to do when we get the screenshot result ?
onScreenshotReady = (pEvent : InfiniteEvent, _pCallbackData) : void =>
{
// the image result
const lInfiniteImage : InfiniteImageInterface = pEvent.attachments;

// if the id does not match, bail out
if (lInfiniteImage.screenshotid !== lScreenshotId)
{
console.log('This is not the expected screenshot id, aborting')
return;
}

// is the image valid ? and base64 encoded ?
if ((lInfiniteImage.width === 0) || (!lInfiniteImage.data) || (!lInfiniteImage.base64))
{
console.log('Unexpected screenshot error, aborting')
return;
}

// create the data url in base64
// even if we did not get the expected format, we still get the result
const lDataUrl : string = 'data:' + lInfiniteImage.format + ';base64,' + lInfiniteImage.data;

// resize the image markup
lImageData.width = lInfiniteImage.width;
lImageData.height = lInfiniteImage.height;
// and set data
lImageData.src = lDataUrl;

// we get back to the size of the 3d view but this is up to the application needs
lInfiniteEngine.unsetFixedResolution();
}

or with async calls :
/** 
* Sample to illustrate the asynchronous screenshot procedure of the InfiniteEngineInterface.
*/
import {
InfiniteEngineInterface, LoadingStates, Vector3,
InfiniteImageInterface, ScreenshotType, AsyncDataLoadedResult, AsyncResultReason, AsyncScreenshotResult
} from 'generated/documentation/appinfiniteapi';

// We try to make a screenshot when all data is loaded

// the div to render the 3D display
let lView3D: HTMLElement;

// created previously, should receive the image data to be displayed to the user (or ask for a download maybe ?)
let lImageData : HTMLImageElement;

// created previously the position of the camera for the screenshot
let lCameraLocation : Vector3;

// created previously the camera center of interest
let lCenterOfInterest : Vector3;

// created previously the 3D engine
let lInfiniteEngine: InfiniteEngineInterface;

const takeScreenshot = async () : Promise<void> =>
{
// bind the 3D rendering to the div (should have been done earlier :) )
lInfiniteEngine.setView(lView3D);

// we will make screenshot of 1024x1024
lInfiniteEngine.setFixedResolution(1024, 1024, 1);

// go to the expected position / location
lInfiniteEngine.getCameraManager().setCameraLocation(lCameraLocation);
lInfiniteEngine.getCameraManager().lookAt(lCenterOfInterest, 0);

// What to do when all data is loaded ?
const lDataLoaded : AsyncDataLoadedResult = await lInfiniteEngine.asyncWaitForDataLoaded();
if (lDataLoaded.reason !== AsyncResultReason.ARR_Success || lDataLoaded.value === undefined)
{
// this is an error that should not happen (perhaps the engine interface has been destroyed ?)
console.log('screenshot procedure failed for some reason');
return;
}
const lDataLoadedState : LoadingStates = lDataLoaded.value.newLoadingState;
switch (lDataLoadedState)
{
case LoadingStates.S_Loading:
// this is an unexpected error
console.log('unexpected error');
return;
case LoadingStates.S_OutOfBudget:
// some fancy message
console.log('Taking a screenshot without everything loaded');
// but we still make a screenshot :)
break;
default:
break;
}
const lScreenshot : AsyncScreenshotResult = await lInfiniteEngine.asyncScreenshot(ScreenshotType.ST_Color, true, 'image/jpeg', 0.95);
if (lScreenshot.reason !== AsyncResultReason.ARR_Success || lScreenshot.value === undefined)
{
// this is an error that may happen (perhaps the engine interface has been destroyed ?, or bad inputs ?)
console.log('screenshot procedure failed for some reason');
return;
}
// What to do when screenshot is ready ?

// the image result
const lInfiniteImage : InfiniteImageInterface = lScreenshot.value;

// is the image valid ? and base64 encoded ?
if ((lInfiniteImage.width === 0) || (!lInfiniteImage.data) || (!lInfiniteImage.base64))
{
console.log('Unexpected screenshot error, aborting')
return;
}

// create the data url in base64
// even if we did not get the expected format, we still get the result
const lDataUrl : string = 'data:' + lInfiniteImage.format + ';base64,' + lInfiniteImage.data;

// resize the image markup
lImageData.width = lInfiniteImage.width;
lImageData.height = lInfiniteImage.height;
// and set data
lImageData.src = lDataUrl;

// we get back to the size of the 3d view but this is up to the application needs
lInfiniteEngine.unsetFixedResolution();
}

takeScreenshot();

Please make sure the destination browser supports promises before using async calls.

Camera manipulation.

The camera is manipulated from the CameraManagerInterface, accessed through getCameraManager. Some default behaviors are available in order to avoid the developer to code a lot of event handling in order to make the camera move in an interesting way. Available behaviors are orbital ones, i.e. the camera moves around a center of interest, but mouse manipulation is different from modes.

You may create animations to move, rotate the camera.

Cut Plane manipulation.

A cut plane is a theoretical 3D plane that "cut" objects. A cut plane (3D Affine hyperplane) is defined by a position P that belong to the plane and a normal N : (Nx,Ny,Nz). Such a plane has the equation : {x,y,z} / Nx.x + Ny.y + Nz.z = dot(N,P). Each vertex on the side of the normal N will be discarded, so every vertex V : {Vx,Vy,Vz} / Nx.Vx + Ny.Vy + Nz.Vz > dot(N,P) will be discarded.

Cut planes are modified through the CutPlaneManagerInterface accessible through getCutPlaneManager.

A CutPlaneManipulatorInterface may be created and bound to a cut plane to display a GUI element that allows the end user to change the cut plane orientation / position through createCutPlaneManipulator.

Object with a visual state S_IgnoreCutPlane will not be affected by cut planes.

/** 
* Sample to illustrate the creation of a cut plane, manipulated with a CutPlaneManipulatorInterface.
*/
import { InfiniteEngineInterface, CutPlaneManagerInterface, Vector3, CutPlaneManipulatorInterface } from 'generated/documentation/appinfiniteapi';

// lEngine has been created previously
let lEngine : InfiniteEngineInterface;

// we want to hide items that are above (and not under), thus the normal is in the positive side.
const lNormal : Vector3 = new Vector3(0, 0, 1);
// any point with z = 10 is ok
const lPoint : Vector3 = new Vector3(Math.random(), Math.random(), 10);
// get the cut plane manager
const lCutPlaneManager : CutPlaneManagerInterface = lEngine.getCutPlaneManager();
const lCutPlaneId = lCutPlaneManager.createCutPlane(lPoint, lNormal);
console.assert(lCutPlaneId !== 0);
// do what you want, the cut plane is working as it is enabled upon creation
// and create a cut plane manipulator to allow the end user to change the cut plane geometry.
const lCutPlaneManipulator : CutPlaneManipulatorInterface = lCutPlaneManager.createCutPlaneManipulator();
// bind the manipulator to the newly created cut plane
lCutPlaneManipulator.setCutPlaneId(lCutPlaneId);
// hide it for the moment, we may need it later
lCutPlaneManipulator.setVisible(false);

Setting cut planes.

Annotations.

The rendering may be enriched to display 2D data representing measures, drawings (Functional Tolerancing and Annotations, Product Manufacturing Information, Measures, etc). These data are basically a 3D plane containing information in form of texts, curves, and symbols in this plane. Data of this type is referred to an Annotation.

3D Primitives.

3D Points, 3D lines, 3D boxes and a single 2D rectangle can be rendered on top of the DMU, with a rendering hint depending on the relative depth between the 3D primitives and the geometries. 3D primitives are accessed through the getPrimitiveManager function (PrimitiveManagerInterface). The colors of the 3D primitive are handled by the PrimitiveManagerMaterialInterface, accessed through getMaterialManager. Materials are accessed by their ids, and modified by their ids. 3D primitives are rendered colored with their material id, and not directly from a color.

3D Points.

The rendering can be enriched with 3D points rendered on top of the geometries, with a rendering hint telling if the point is over or under a geometry.

point display
Point Creation sample :
/** 
* Sample to explain how to create 3d points on top of the rendering (PrimitiveManagerPointInterface).
*/
import { InfiniteEngineInterface, PrimitiveManagerMaterialInterface, PrimitiveManagerPointInterface, Vector4, Vector3 } from 'generated/documentation/appinfiniteapi';

// created previously
let lInfiniteEngine : InfiniteEngineInterface;
// created previously, the point position
let lPointPosition : Vector3;

// the material for the inner point color
let lInnerPointColorMaterial : number = -1;
// the material for the outer point color
let lOuterPointColorMaterial : number = -1;
// the primitive material manager
const lPrimitiveMaterialManager : PrimitiveManagerMaterialInterface = lInfiniteEngine.getPrimitiveManager().getMaterialManager();
// the point manager
const lPointManager : PrimitiveManagerPointInterface = lInfiniteEngine.getPrimitiveManager().getPointManager();

// inner point color is white opaque (1 as last parameter)
const lInnerPointColor : Vector4 = new Vector4(1, 1, 1, 1);
// outer point color is black semi transparent (0.5 as last parameter)
const lOuterPointColor : Vector4 = new Vector4(0, 0, 0, 0.5);

// create materials
lInnerPointColorMaterial = lPrimitiveMaterialManager.createMaterial(lInnerPointColor);
lOuterPointColorMaterial = lPrimitiveMaterialManager.createMaterial(lOuterPointColor);

// and create the point
const lPointId : number = lPointManager.createPoint(
// position
lPointPosition,
// sizes (quite a large point :) )
40,
35,
// colors
lInnerPointColorMaterial,
lOuterPointColorMaterial
);

console.log('Point id is ' + lPointId);

Creating a point.

3D Lines.

The rendering can be enriched with 3D lines rendered on top of the geometries.

line display
Line Creation sample :
/** 
* Sample to explain how to create 3d lines on top of the rendering (PrimitiveManagerLineInterface).
*/
import { InfiniteEngineInterface, PrimitiveManagerMaterialInterface, PrimitiveManagerLineInterface, Vector4, Vector3 } from 'generated/documentation/appinfiniteapi';

// created previously
let lInfiniteEngine : InfiniteEngineInterface;
// created previously, the segment point position 1
let lLinePosition1 : Vector3;
// created previously, the segment point position 2
let lLinePosition2 : Vector3;

// the material for the line color
let lLineColorMaterial : number = -1;
// the primitive material manager
const lPrimitiveMaterialManager : PrimitiveManagerMaterialInterface = lInfiniteEngine.getPrimitiveManager().getMaterialManager();
// the line manager
const lLineManager : PrimitiveManagerLineInterface = lInfiniteEngine.getPrimitiveManager().getLineManager();
// line color is white opaque (1 as last parameter)
const lLineColor : Vector4 = new Vector4(1, 1, 1, 1);

// create material
lLineColorMaterial = lPrimitiveMaterialManager.createMaterial(lLineColor);

// and create the line
const lLineId : number = lLineManager.createLine(
// segment extents
lLinePosition1,
lLinePosition2,
lLineColorMaterial,
// line width
5
);

console.log('Line id is ' + lLineId);

Creating a line.

3D Boxes.

The rendering can be enriched with 3D boxes rendered on top of the geometries, with a rendering hint telling if the edge/face is over or under a geometry.

box display
Box Creation sample :
/** 
* Sample to explain how to create 3d boxes on top of the rendering (PrimitiveManagerBoxInterface).
*/
import { InfiniteEngineInterface, PrimitiveManagerMaterialInterface, PrimitiveManagerBoxInterface, Vector4, Vector3 } from 'generated/documentation/appinfiniteapi';

// created previously
let lInfiniteEngine : InfiniteEngineInterface;
// created previously, the box center
let lBoxCenter : Vector3;
// created previously, the box half extent in x,y,z
let lBoxHalfExtent : Vector3;

// the material edges of the box
let lEdgeColorMaterial : number = -1;
// the material for the faces of the box
let lFaceColorMaterial : number = -1;
// the primitive material manager
const lPrimitiveMaterialManager : PrimitiveManagerMaterialInterface = lInfiniteEngine.getPrimitiveManager().getMaterialManager();
// the box manager
const lBoxManager : PrimitiveManagerBoxInterface = lInfiniteEngine.getPrimitiveManager().getBoxManager();

// face color is white opaque (1 as last parameter)
const lFaceColor : Vector4 = new Vector4(1, 1, 1, 1);
// edge color is red semi transparent (0.5 as last parameter)
const lEdgeColor : Vector4 = new Vector4(1, 0, 0, 0.5);

// create materials
lFaceColorMaterial = lPrimitiveMaterialManager.createMaterial(lFaceColor);
lEdgeColorMaterial = lPrimitiveMaterialManager.createMaterial(lEdgeColor);

// and create the box
const lBoxId : number = lBoxManager.createBox(
// center, half extent
lBoxCenter,
lBoxHalfExtent,
// colors
lEdgeColorMaterial,
lFaceColorMaterial,
// line width
5
);

console.log('Box id is ' + lBoxId);

Creating a Box.

2D rectangle (rubber band).

The rendering can be enriched with a single 2D rectangle rendered on top of the geometries. The color cannot be changed.

rubber band display
Rectangle usage sample :
/** 
* Sample to explain how to create a 2D rectangle on top of the rendering (PrimitiveManagerRubberBandInterface).
*/
import { InfiniteEngineInterface, PrimitiveManagerRubberBandInterface, Vector2, Rectangle } from 'generated/documentation/appinfiniteapi';

// created previously
let lInfiniteEngine : InfiniteEngineInterface;
const lSelectionRectangle : Rectangle = new Rectangle();

// created previously, the rectangle extents
let lRectanglePosition1 : Vector2;
let lRectanglePosition2 : Vector2;

// the rubber band manager
const lRubberBandManager : PrimitiveManagerRubberBandInterface = lInfiniteEngine.getPrimitiveManager().getRubberBandManager();

// compute rectangle geometry from the 2 extent points
lSelectionRectangle.x = Math.min(lRectanglePosition1.x, lRectanglePosition2.x);
lSelectionRectangle.y = Math.min(lRectanglePosition1.y, lRectanglePosition2.y);
lSelectionRectangle.width = Math.abs(lRectanglePosition1.x - lRectanglePosition2.x);
lSelectionRectangle.height = Math.abs(lRectanglePosition1.y - lRectanglePosition2.y);

// make sure rectangle is correct
console.assert(lSelectionRectangle.isValid() && (!lSelectionRectangle.isEmpty()));

// set rectangle and display it
lRubberBandManager.setRubberBandRectangle(lSelectionRectangle);
lRubberBandManager.setRubberBandVisible(true);

Using a Rectangle.

WebXR (experimental).

You may use the InfiniteEngineInterface api with WebXR sessions :

/** 
* Sample to illustrate using a webxr session.
*/
import { InfiniteEngineInterface, InfiniteEngineInterfaceSignal, InfiniteEvent, InfiniteXRSession, CameraManagerInterfaceSignal, InfiniteXRReferenceSpace } from 'generated/documentation/appinfiniteapi';

// We try to make a screenshot when all data is loaded

// created previously the 3D engine
let lInfiniteEngine: InfiniteEngineInterface;
// the webXR session
let lCurSession : InfiniteXRSession;

// store the XRSession when ready
lInfiniteEngine.addEventListener(
InfiniteEngineInterfaceSignal.XRSessionReady,
(pEvent: InfiniteEvent) : void =>
{
lCurSession = pEvent.attachments;
}
);

// make some fancy things on camera changes
// we may have used InfiniteEngineInterfaceSignal.DisplayDone
// to be called each frame
lInfiniteEngine.getCameraManager().addEventListener(
CameraManagerInterfaceSignal.CameraLocationChanged,
(_pEvent: InfiniteEvent) : void =>
{
if (!lCurSession)
{
return;
}
const lXRRefSpace : InfiniteXRReferenceSpace | undefined = lInfiniteEngine.getCameraManager().getXRReferenceFrame();
if (!lXRRefSpace)
{
return;
}
// make some computations with XRSession inputs
console.log(lCurSession.inputSources.length);
}
);

// bind the 3D rendering to the div (should have been done earlier :) )
lInfiniteEngine.setView(undefined, { type: 'webxr', options: {} });

Please note that dedicated hardware is required to use WebXR. See [https://developer.mozilla.org/en-US/docs/Web/API/WebXR_Device_API/Fundamentals](https://developer.mozilla.org/en-US/docs/Web/API/WebXR_Device_API/Fundamentals).
3D Rendering

See

Hierarchy

Methods

  • Adds a listener to an event type.

    When an event of the type pType fires, the callback pListener will be called. This function returns a unique string id that may be used in removeEventListenerById to allow simple listener removal. It is possible to add an object that will be included in the callback to avoid creating too many closures.

    Returns

    The id of the inserted callback (actually an UUID).

    Parameters

    • pType: string
      in
      The type of the event pListener will be called upon.
    • pListener: tListenerCallback
      in
      The listener function that fires when the given event type occurs.
    • pObject: undefined | Object
      in
      The optional object the callback will be called with when the given event fires.

    Returns string

  • Adds a listener to an event type.

    When an event of the type pType fires, the callback pListener will be called. This function returns a unique string id that may be used in removeEventListenerById to allow simple listener removal.

    Returns

    The id of the inserted callback (actually an UUID).

    Parameters

    • pType: string
      in
      The type of the event pListener will be called upon.
    • pListener: tListenerCallback
      in
      The listener function that fires when the given event type occurs.

    Returns string

  • Requests an asynchronous pick in the 3D at coordinates [pX,pY] ((0,0) is on the upper left of screen).

    The result is an AsyncPickingResult.

    Returns

    A promise. The promise is resolved with the reason (success, cancelled, disposed, bad input). In case of success, the promise is resolved with the picking attachment.

    Parameters

    • pX: number
      in
      Number between 0 and view3d.width-1, origin is the left side of the view (as retrieved from the MouseEvent).
    • pY: number
      in
      Number between 0 and view3d.height-1, origin is the upper side of the view (as retrieved from the MouseEvent).

    Returns Promise<AsyncPickingResult>

  • Requests an asynchronous pick in the 3D from a 3D ray.

    The 3D is not required to come from the position of the camera, but the ray must be oriented toward the direction of the camera (the dot vector between the direction of the camera and the direction of the ray must be positive). The ray is a half line that comes from the origin and follows the direction to the infinity.

    Fires the event Picked when the result is ready. Attachment is a PickingAttachment. Please use getLastPickingRequestId to know the pick request id in case of multiple pick requests.

    /** 
    * Sample to illustrate the handling of an asynchronous ray pick in an InfiniteEngineInterface.
    */
    import {
    InfiniteEngineInterface, InfiniteFactory, MetadataManagerInterface, PickingAttachment, PickingAttachmentItem, Vector3, VisualStates, AsyncPickingResult,
    AsyncResultReason,
    } from 'generated/documentation/appinfiniteapi';

    // created previously
    let lMetadataManager : MetadataManagerInterface;
    // the div to render to
    let lView3D: HTMLElement;

    // create an 3D engine
    const lInfiniteEngine: InfiniteEngineInterface = InfiniteFactory.CreateInfiniteEngine(lMetadataManager);

    // We pick a rectangle if big enough, else only a point
    let pickAtImpl : () => void = undefined;

    // created previously : the origin of the 3D ray to pick from
    let lPickRayOrigin : Vector3;

    // created previously : the direction of the 3D ray to pick from
    let lPickRayDirection : Vector3;

    // bind the 3D rendering to the div
    lInfiniteEngine.setView(lView3D);

    // ####################################################################################################################################
    // ############################################ PICKING ###############################################################################
    // ####################################################################################################################################

    // What to do on pick ?
    const onPicking = (pAttachment: PickingAttachment) : void =>
    {
    // care only about 3d geometries (no line, point, box)
    const l3dAttachment: PickingAttachmentItem[] | undefined = pAttachment.geometric;

    let lFirstGeometricId: number = 0;
    let l3dPosition: Vector3 | undefined = undefined;
    if (l3dAttachment !== undefined && l3dAttachment.length > 0)
    {
    lFirstGeometricId = l3dAttachment[0].instanceId;
    l3dPosition = l3dAttachment[0].position;
    }
    // clear selected state on pick
    let lWasSelected: boolean = false;
    if (lFirstGeometricId !== 0)
    {
    const lGeomState = lInfiniteEngine.getGeometricState(lFirstGeometricId);
    lWasSelected = ((lGeomState & VisualStates.S_Selected) !== 0);
    }
    // if multiple selections => do not change the selected state of a single geometry
    // but select all the relevant 3D data instead
    if (l3dAttachment && l3dAttachment.length > 1)
    {
    lWasSelected = false;
    }
    // unselect everyone
    lInfiniteEngine.updateGeometricStateForAll(VisualStates.S_Selected, ~VisualStates.S_Selected);
    // and begin
    if (lFirstGeometricId !== 0 && !lWasSelected && l3dAttachment)
    {
    // update visual state of selected items
    const lIds = new Uint32Array(l3dAttachment.length);
    for (let i = 0; i < l3dAttachment.length; ++i) {
    lIds[i] = l3dAttachment[i].instanceId;
    }
    lInfiniteEngine.updateGeometricState(lIds, VisualStates.S_Selected, VisualStates.S_Selected);
    }
    };

    // We pick a rectangle if big enough, else only a point
    pickAtImpl = async () : Promise<any> =>
    {
    const lPickingResult : AsyncPickingResult = await lInfiniteEngine.asyncPickFromRay(lPickRayOrigin, lPickRayDirection);
    if (lPickingResult.reason !== AsyncResultReason.ARR_Success || lPickingResult.value === undefined)
    {
    return;
    }
    onPicking(lPickingResult.value);
    }

    pickAtImpl();

    There are some limitations to the 3D ray pick : * Only 3D elements actually rendered may be picked (no ray pick outside the frustum). * The pick ray algorithm rely on the projection of the surfaces to the near plane, objects that are less than 2 pixels wide and 2 pixels high cannot be picked.

    Returns

    A promise. The promise is resolved with the reason (success, cancelled, disposed, bad input). In case of success, the promise is resolved with the picking attachment.

    Parameters

    • pOrigin: Vector3
      in
      The origin of the ray.
    • pDirection: Vector3
      in
      The direction of the ray.

    Returns Promise<AsyncPickingResult>

  • Requests an asynchronous pick in the 3D from a screen space rectangle.

    (0,0) is on the upper left of screen. The result is an AsyncPickingResult.

    Returns

    A promise. The promise is resolved with the reason (success, cancelled, disposed, bad input). In case of success, the promise is resolved with the picking attachment.

    Parameters

    • pRectangle: Rectangle
      in
      The screen space rectangle to pick from. Origin of the screen is the top-left of the view (as retrieved from the MouseEvent).

    Returns Promise<AsyncPickingResult>

  • Requests an asynchronous screenshot.

    The current image of the display is grabbed (without the navigation cube and manipulators such as cut plane manipulators), or the geometric instance ids, depending on the screenshot request type, and a screenshot promise is returned.

    The resulting screenshot data will be base64 encoded if pInBase64 is set to true (data will be a string, else a UInt8Array).

    When using ST_Color, pFormat tells the resulting format of the data, 'image/png' is by default. Available formats are the same as the HTMLCanvasElement.toDataURL() or HTMLCanvasElement.toBlob() calls. The API adds the 'image/raw' format to deal with individual pixels if requested (without image encoding). pQuality is a number in the [0,1] range, telling the expected quality if the requested format is a lossy compression scheme, such as 'image/jpeg'. If the requested format is not handled by the browser, 'image/png' type will be used.

    When using other formats, pFormat and pQuality are ignored.

    If pInBase64 is true, you may create a data url with the following code :

    /** 
    * Sample to illustrate the asynchronous screenshot procedure of the InfiniteEngineInterface.
    */
    import {
    InfiniteEngineInterface, LoadingStates, Vector3,
    InfiniteImageInterface, ScreenshotType, AsyncDataLoadedResult, AsyncResultReason, AsyncScreenshotResult
    } from 'generated/documentation/appinfiniteapi';

    // We try to make a screenshot when all data is loaded

    // the div to render the 3D display
    let lView3D: HTMLElement;

    // created previously, should receive the image data to be displayed to the user (or ask for a download maybe ?)
    let lImageData : HTMLImageElement;

    // created previously the position of the camera for the screenshot
    let lCameraLocation : Vector3;

    // created previously the camera center of interest
    let lCenterOfInterest : Vector3;

    // created previously the 3D engine
    let lInfiniteEngine: InfiniteEngineInterface;

    const takeScreenshot = async () : Promise<void> =>
    {
    // bind the 3D rendering to the div (should have been done earlier :) )
    lInfiniteEngine.setView(lView3D);

    // we will make screenshot of 1024x1024
    lInfiniteEngine.setFixedResolution(1024, 1024, 1);

    // go to the expected position / location
    lInfiniteEngine.getCameraManager().setCameraLocation(lCameraLocation);
    lInfiniteEngine.getCameraManager().lookAt(lCenterOfInterest, 0);

    // What to do when all data is loaded ?
    const lDataLoaded : AsyncDataLoadedResult = await lInfiniteEngine.asyncWaitForDataLoaded();
    if (lDataLoaded.reason !== AsyncResultReason.ARR_Success || lDataLoaded.value === undefined)
    {
    // this is an error that should not happen (perhaps the engine interface has been destroyed ?)
    console.log('screenshot procedure failed for some reason');
    return;
    }
    const lDataLoadedState : LoadingStates = lDataLoaded.value.newLoadingState;
    switch (lDataLoadedState)
    {
    case LoadingStates.S_Loading:
    // this is an unexpected error
    console.log('unexpected error');
    return;
    case LoadingStates.S_OutOfBudget:
    // some fancy message
    console.log('Taking a screenshot without everything loaded');
    // but we still make a screenshot :)
    break;
    default:
    break;
    }
    const lScreenshot : AsyncScreenshotResult = await lInfiniteEngine.asyncScreenshot(ScreenshotType.ST_Color, true, 'image/jpeg', 0.95);
    if (lScreenshot.reason !== AsyncResultReason.ARR_Success || lScreenshot.value === undefined)
    {
    // this is an error that may happen (perhaps the engine interface has been destroyed ?, or bad inputs ?)
    console.log('screenshot procedure failed for some reason');
    return;
    }
    // What to do when screenshot is ready ?

    // the image result
    const lInfiniteImage : InfiniteImageInterface = lScreenshot.value;

    // is the image valid ? and base64 encoded ?
    if ((lInfiniteImage.width === 0) || (!lInfiniteImage.data) || (!lInfiniteImage.base64))
    {
    console.log('Unexpected screenshot error, aborting')
    return;
    }

    // create the data url in base64
    // even if we did not get the expected format, we still get the result
    const lDataUrl : string = 'data:' + lInfiniteImage.format + ';base64,' + lInfiniteImage.data;

    // resize the image markup
    lImageData.width = lInfiniteImage.width;
    lImageData.height = lInfiniteImage.height;
    // and set data
    lImageData.src = lDataUrl;

    // we get back to the size of the 3d view but this is up to the application needs
    lInfiniteEngine.unsetFixedResolution();
    }

    takeScreenshot();

    The result is an [AsyncScreenshotResult](AsyncScreenshotResult.html).

    Returns

    A promise. The promise is resolved with the reason (success, cancelled, disposed, bad input). In case of success, the promise is resolved with the screenshot content.

    Parameters

    • pScreenshotType: ScreenshotType
      in
      The request screenshot type (image, geometric instance ids, etc).
    • pInBase64: boolean
      in
      If set to true, [data](InfiniteImageInterface.html#data) will be a base64 string.
    • Optional pFormat: string
      in
      The expected format of the resulting screenshot data ('image/png' by default).
    • Optional pQuality: number
      in
      The expected quality of the resulting screenshot data, in the [0,1] range in case of lossy compression formats.

    Returns Promise<AsyncScreenshotResult>

  • Requests an asynchronous wait for data loaded.

    The promise is signaled when the data loading process is over, i.e. when getResourceLoadingState returns S_AllLoaded or S_OutOfBudget.

    An example with a screenshot procedure :

    /** 
    * Sample to illustrate the asynchronous screenshot procedure of the InfiniteEngineInterface.
    */
    import {
    InfiniteEngineInterface, LoadingStates, Vector3,
    InfiniteImageInterface, ScreenshotType, AsyncDataLoadedResult, AsyncResultReason, AsyncScreenshotResult
    } from 'generated/documentation/appinfiniteapi';

    // We try to make a screenshot when all data is loaded

    // the div to render the 3D display
    let lView3D: HTMLElement;

    // created previously, should receive the image data to be displayed to the user (or ask for a download maybe ?)
    let lImageData : HTMLImageElement;

    // created previously the position of the camera for the screenshot
    let lCameraLocation : Vector3;

    // created previously the camera center of interest
    let lCenterOfInterest : Vector3;

    // created previously the 3D engine
    let lInfiniteEngine: InfiniteEngineInterface;

    const takeScreenshot = async () : Promise<void> =>
    {
    // bind the 3D rendering to the div (should have been done earlier :) )
    lInfiniteEngine.setView(lView3D);

    // we will make screenshot of 1024x1024
    lInfiniteEngine.setFixedResolution(1024, 1024, 1);

    // go to the expected position / location
    lInfiniteEngine.getCameraManager().setCameraLocation(lCameraLocation);
    lInfiniteEngine.getCameraManager().lookAt(lCenterOfInterest, 0);

    // What to do when all data is loaded ?
    const lDataLoaded : AsyncDataLoadedResult = await lInfiniteEngine.asyncWaitForDataLoaded();
    if (lDataLoaded.reason !== AsyncResultReason.ARR_Success || lDataLoaded.value === undefined)
    {
    // this is an error that should not happen (perhaps the engine interface has been destroyed ?)
    console.log('screenshot procedure failed for some reason');
    return;
    }
    const lDataLoadedState : LoadingStates = lDataLoaded.value.newLoadingState;
    switch (lDataLoadedState)
    {
    case LoadingStates.S_Loading:
    // this is an unexpected error
    console.log('unexpected error');
    return;
    case LoadingStates.S_OutOfBudget:
    // some fancy message
    console.log('Taking a screenshot without everything loaded');
    // but we still make a screenshot :)
    break;
    default:
    break;
    }
    const lScreenshot : AsyncScreenshotResult = await lInfiniteEngine.asyncScreenshot(ScreenshotType.ST_Color, true, 'image/jpeg', 0.95);
    if (lScreenshot.reason !== AsyncResultReason.ARR_Success || lScreenshot.value === undefined)
    {
    // this is an error that may happen (perhaps the engine interface has been destroyed ?, or bad inputs ?)
    console.log('screenshot procedure failed for some reason');
    return;
    }
    // What to do when screenshot is ready ?

    // the image result
    const lInfiniteImage : InfiniteImageInterface = lScreenshot.value;

    // is the image valid ? and base64 encoded ?
    if ((lInfiniteImage.width === 0) || (!lInfiniteImage.data) || (!lInfiniteImage.base64))
    {
    console.log('Unexpected screenshot error, aborting')
    return;
    }

    // create the data url in base64
    // even if we did not get the expected format, we still get the result
    const lDataUrl : string = 'data:' + lInfiniteImage.format + ';base64,' + lInfiniteImage.data;

    // resize the image markup
    lImageData.width = lInfiniteImage.width;
    lImageData.height = lInfiniteImage.height;
    // and set data
    lImageData.src = lDataUrl;

    // we get back to the size of the 3d view but this is up to the application needs
    lInfiniteEngine.unsetFixedResolution();
    }

    takeScreenshot();

    Please make sure the destination browser supports promises before using async calls.

    Returns

    A promise. The promise is resolved with the reason (success, cancelled, disposed, bad input). In case of success, the promise is resolved with the resource loading state.

    Returns Promise<AsyncDataLoadedResult>

  • Enables / disables anti aliasing.

    Anti aliasing is disabled by default.

    Parameters

    • pEnable: boolean
      in
      If set, enables the anti aliasing.

    Returns void

  • Enables / disables the copyrighted watermark.

    The copyrighted watermark is the information provided on the bottom right of the rendering that tells about the authors of the javascript API :) .

    copyrighted watermark display
    The copyrighted watermark is enabled by default.

    Parameters

    • pEnabled: boolean
      in
      If set, enables the copyrighted watermark on the rendering.

    Returns void

  • Enables / disables edge detection mechanism.

    Edge detection is disabled by default.

    Parameters

    • pEnable: boolean
      in
      If set, enables the edge detection mechanism.

    Returns void

  • Gets the current background.

    If the background is a grid then getBackgroundColor returns false and pBackgroundColor is left intact.

    If the background is a color then getBackgroundColor returns true and pBackgroundColor is set with the current background color.

    Returns

    true if the background is a color, false if it is a grid.

    Parameters

    • pBackgroundColor: Vector3
      out
      The current background color (if the background is a color).

    Returns boolean

  • Tells if setFixedResolution is in use at the moment, and gets the fixed resolution is setFixedResolution is in use.

    If setFixedResolution(pWidth, pHeight, pWindowRatio) is in use, pResolution.x will be equal to Math.ceil(pWidth), pResolution.y will be equal to Math.ceil(pHeight), and pResolution.z will be equal to pWindowRatio and true is returned.

    If setFixedResolution is not in use, false is returned and pResolution is left as is.

    Returns

    true if setFixedResolution is in use, else false.

    Parameters

    • pResolution: Vector3
      out
      The fixed resolution parameters if [setFixedResolution](InfiniteEngineInterface.html#setFixedResolution) has been called.

    Returns boolean

  • Gets the visual state (Visible/hide/Ghost/Ignore cut plane) of the given geometric instance id.

    The visual state is a bit field that allows to change a lot of geometric instance ids at once.

    Returns

    The visual state of the given element.

    See

    VisualStates

    Parameters

    • pGeometricId: number
      in
      The geometric instance id of the element to get.

    Returns number

  • Computes the Axis Aligned Bounding Box of geometries which have the specified visual state.

    Each geometry visual state is intersected with the pBitMask. If the resulting value is pBitValue then the geometry bounding box will be used in the computation.

    Example : computing the axis aligned bounding box of visible geometries :

    /** 
    * Sample to illustrate the computing of the AABB of the visible `geometric instances`.
    */
    import { InfiniteEngineInterface, VisualStates, AABB } from 'generated/documentation/appinfiniteapi';

    // created previously
    let lInfiniteEngine : InfiniteEngineInterface;
    // to get the result of the AABB computation
    const lVisibleAABB : AABB = new AABB();
    // we need to check only visible / hidden flag
    const lBitMask : number = VisualStates.S_Hidden;
    // we want to get all geometries that are not hidden (~VisualStates.S_Hidden)
    // easier with 0 :)
    const lVisibleValueBit : number = 0;

    // compute the AABB of visible geometries :
    lInfiniteEngine.getGeometryAABB(lBitMask, lVisibleValueBit, lVisibleAABB);

    Please refer to the [VisualStates](../enums/VisualStates.html) for a list of possible values.

    Returns

    true if at least one geometry is involved in the computation, else pAABB is left unchanged and false is returned.

    Parameters

    • pBitMask: number
      in
      the bit mask ("ORed" value of the [VisualStates](../enums/VisualStates.html)) of the states to check.
    • pBitValue: number
      in
      the bit value ("ORed" value of the [VisualStates](../enums/VisualStates.html)) of the states that will be checked.
    • pAABB: AABB
      out
      the computed AABB for the given bit composition of [VisualStates](../enums/VisualStates.html).

    Returns boolean

  • Gets the last request id of the running pickAt or pickRect call.

    Just call getLastPickingRequestId after the call to pickAt or pickRect to know the request id.

    If no picking is running, then returns an empty string.

    Returns

    The id of the last picking request.

    Returns string

  • Gets the loading state of the engine.

    Tells if the engine has finished loading resources and if so, if the budget was sufficient to load all required data.

    Returns

    The LoadingStates of the engine.

    Returns LoadingStates

  • Gets the version of the 3djuump infinite API.

    Returns

    The version of the 3djuump infinite API.

    Deprecated

    Please use getVersion.

    Returns string

  • Gets the HTML element used to render the 3D.

    Returns

    The HTML element used to render 3D or undefined if not set.

    Returns undefined | HTMLElement

  • (Experimental) Gets the WebGLRenderingContext used to render things.

    Use this object at your own risks !!!.

    Returns

    The WebGLRenderingContext used to render things on the 3D view.

    Returns undefined | WebGLRenderingContext

  • (WebXR) Gets the current XRFrame.

    The XRFrame is valid only during the time of the rendering loop, you may access the given frame only when connecting to CameraManagerInterface events, or DisplayDone.

    If the session is not an XRSession, or if calld outside of the rendering loop, returns undefined.

    Returns

    The current XRFrame if called inside the rendering loop in an XR session, else undefined.

    Returns any

  • Tells if the EventDispatcher has such a callback registered for the given event type.

    Returns

    true if such a listener is installed for the given type of event.

    Parameters

    • pType: string
      in
      The type of the event to test.
    • pListener: tListenerCallback
      in
      The listener function that gets tested.

    Returns boolean

  • Tells if anti aliasing is enabled.

    Returns

    true if anti aliasing is enabled.

    Returns boolean

  • Tells if backface culling is enabled, but this value is meaningless.

    Back-face culling is a rendering optimization that allows the 3d rendering to display the triangles only one-sided, this setup is now enforced by the DMU maintainer globally, or for individual geometries.

    Returns

    true or false but this value is meaningless.

    Deprecated

    isBackfaceCullingEnabled will be removed in future release.

    Returns boolean

  • Tells if the copyrighted watermark is enabled.

    The copyrighted watermark is the information provided on the bottom right of the rendering that tells about the authors of the javascript API :) .

    copyrighted watermark display
    This is set by [enableCopyrightedWatermark](InfiniteEngineInterface.html#enableCopyrightedWatermark).

    Returns

    true if the copyrighted watermark is enabled.

    Returns boolean

  • Tells if edge detection mechanism is enabled.

    Returns

    true if edge detection is enabled.

    Returns boolean

  • Tells if the renderer is not computing any frame.

    If nothing should be done, then the previous frame is displayed without any intensive computation.

    Returns

    true if the renderer is recycling the previous frame.

    Returns boolean

  • Requests an asynchronous pick in the 3D at coordinates [pX,pY] ((0,0) is on the upper left of screen).

    Fires the event Picked when the result is ready. Attachment is a PickingAttachment. Please use getLastPickingRequestId to know the pick request id in case of multiple pick requests.

    Returns

    true if [pX pY] is inside the 3D area.

    Parameters

    • pX: number
      in
      Number between 0 and view3d.width-1, origin is the left side of the view (as retrieved from the MouseEvent).
    • pY: number
      in
      Number between 0 and view3d.height-1, origin is the upper side of the view (as retrieved from the MouseEvent).

    Returns boolean

  • Requests an asynchronous pick in the 3D from a 3D ray.

    The 3D is not required to come from the position of the camera, but the ray must be oriented toward the direction of the camera (the dot vector between the direction of the camera and the direction of the ray must be positive). The ray is a half line that comes from the origin and follows the direction to the infinity.

    Fires the event Picked when the result is ready. Attachment is a PickingAttachment. Please use getLastPickingRequestId to know the pick request id in case of multiple pick requests.

    /** 
    * Sample to illustrate the handling of a 3d ray pick in an InfiniteEngineInterface.
    */
    import { InfiniteEngineInterface, InfiniteFactory, MetadataManagerInterface, PickingAttachment, PickingAttachmentItem, Vector3, VisualStates, InfiniteEngineInterfaceSignal, Rectangle, InfiniteEvent, PrimitiveManagerInterface } from 'generated/documentation/appinfiniteapi';

    // created previously
    let lMetadataManager : MetadataManagerInterface;
    // the div to render to
    let lView3D: HTMLElement;

    // create an 3D engine
    const lInfiniteEngine: InfiniteEngineInterface = InfiniteFactory.CreateInfiniteEngine(lMetadataManager);

    // What to do on pick ?
    let onPicking : (pEvent : InfiniteEvent, _pCallbackData) => void = undefined;

    // created previously : the origin of the 3D ray to pick from
    let lPickRayOrigin : Vector3;

    // created previously : the direction of the 3D ray to pick from
    let lPickRayDirection : Vector3;

    // bind the 3D rendering to the div
    lInfiniteEngine.setView(lView3D);

    // ####################################################################################################################################
    // ############################################ PICKING ###############################################################################
    // ####################################################################################################################################

    // What to do on pick ?
    onPicking = (pEvent : InfiniteEvent, _pCallbackData) : void =>
    {
    const lAttachment: PickingAttachment = <PickingAttachment>pEvent.attachments;
    // care only about 3d geometries (no line, point, box)
    const l3dAttachment: PickingAttachmentItem[] | undefined = lAttachment.geometric;

    let lFirstGeometricId: number = 0;
    let l3dPosition: Vector3 | undefined = undefined;
    if (l3dAttachment !== undefined && l3dAttachment.length > 0)
    {
    lFirstGeometricId = l3dAttachment[0].instanceId;
    l3dPosition = l3dAttachment[0].position;
    }
    // clear selected state on pick
    let lWasSelected: boolean = false;
    if (lFirstGeometricId !== 0)
    {
    const lGeomState = lInfiniteEngine.getGeometricState(lFirstGeometricId);
    lWasSelected = ((lGeomState & VisualStates.S_Selected) !== 0);
    }
    // if multiple selections => do not change the selected state of a single geometry
    // but select all the relevant 3D data instead
    if (l3dAttachment && l3dAttachment.length > 1)
    {
    lWasSelected = false;
    }
    // unselect everyone
    lInfiniteEngine.updateGeometricStateForAll(VisualStates.S_Selected, ~VisualStates.S_Selected);
    // and begin
    if (lFirstGeometricId !== 0 && !lWasSelected && l3dAttachment)
    {
    // update visual state of selected items
    const lIds = new Uint32Array(l3dAttachment.length);
    for (let i = 0; i < l3dAttachment.length; ++i) {
    lIds[i] = l3dAttachment[i].instanceId;
    }
    lInfiniteEngine.updateGeometricState(lIds, VisualStates.S_Selected, VisualStates.S_Selected);
    }
    };

    // and bind the callback on pick result
    lInfiniteEngine.addEventListener(InfiniteEngineInterfaceSignal.Picked, onPicking);

    // pick from a 3d Ray
    lInfiniteEngine.pickFromRay(lPickRayOrigin, lPickRayDirection);

    There are some limitations to the 3D ray pick : * Only 3D elements actually rendered may be picked (no ray pick outside the frustum). * The pick ray algorithm rely on the projection of the surfaces to the near plane, objects that are less than 2 pixels wide and 2 pixels high cannot be picked.

    Returns

    true if the picking request is accepted and a pick result will be received soon.

    Parameters

    • pOrigin: Vector3
      in
      The origin of the ray.
    • pDirection: Vector3
      in
      The direction of the ray.

    Returns boolean

  • Gets the 3D representation of a ray from the camera to the normalized screen ray position.

    (0,0) is the upper left of screen. (1,1) is the bottom right of screen. The 3D representation is expressed as a position (the camera position) and a direction. Making a pickRay(0,0,lDir0,lCamPos), pickRay(0,1,lDir1,lCamPos), pickRay(1,0,lDir2,lCamPos), pickRay(1,0,lDir3,lCamPos) effectively stores the limiting rays of the view frustum.

    Returns

    true if [pX pY] was inside [0:1].

    Parameters

    • pX: number
      in
      Number between 0 and 1, 0 is the left side of the view.
    • pY: number
      in
      Number between 0 and 1, 0 is the upper side of the view.
    • pPickRayOut: Vector3
      out
      3D Vector direction of the picked ray.
    • pOrigin: Vector3
      out
      3D Vector origin of the picked ray (i.e. position of the camera).

    Returns boolean

  • Requests an asynchronous pick in the 3D from a screen space rectangle.

    (0,0) is on the upper left of screen. Fires the event Picked when the result is ready. Attachment is a PickingAttachment. Please use getLastPickingRequestId to know the pick request id in case of multiple pick requests.

    Returns

    true if the rectangle is valid and not empty.

    Parameters

    • pRectangle: Rectangle
      in
      the screen space rectangle to pick from. Origin of the screen is the top-left of the view (as retrieved from the MouseEvent).

    Returns boolean

  • Projects the given 3D point on the screen.

    The resulting screen coordinates in pScreenCoordinatesOut are normalized between 0 and 1, (0,0) is the upper left of screen, (1,1) is the bottom right of screen.

    Returns

    true if the view3D was set and if the point can be projected onto the screen.

    Parameters

    • pPoint: Vector3
      in
      The 3D point to project.
    • pScreenCoordinatesOut: Vector2
      out
      The resulting 2D normalized projected point in the range [0:1].

    Returns boolean

  • Removes a listener from an event type.

    If no such listener is found, then the function returns false and does nothing. You must use the exact parameters that were used in addEventListener to actually remove the listener.

    Returns

    true if the callback was removed else false.

    Parameters

    • pType: string
      in
      The type of the listener that gets removed.
    • pListener: tListenerCallback

      The listener function that gets removed.

    • pObject: undefined | Object

      The listener object that was used when addEventListener was called.

    Returns boolean

  • Removes a listener from an event type.

    If no such listener is found, then the function returns false and does nothing. You must use the exact parameters that were used in addEventListener to actually remove the listener.

    Returns

    true if the callback was removed else false.

    Parameters

    • pType: string
      in
      The type of the listener that gets removed.
    • pListener: tListenerCallback

      The listener function that gets removed.

    Returns boolean

  • Removes a listener by its id.

    If no such listener is found, then the function returns false and does nothing. You must use the return value of addEventListener to actually remove the listener.

    Returns

    true if the callback was removed else false.

    Parameters

    • pId: string
      in
      The id returned by the call to [addEventListener](InfiniteEngineInterface.html#addEventListener) that you want to remove.

    Returns boolean

  • Triggers an asynchronous screenshot request.

    The current image of the display is grabbed (without the navigation cube and manipulators such as cut plane manipulators), or the geometric instance ids, depending on the screenshot request type, and a screenshot request id is returned. An invalid screenshot request is an empty string.

    If the screenshot request can be started, then a ScreenshotReady signal will be fired shortly after.

    The resulting screenshot data will be base64 encoded if pInBase64 is set to true (data will be a string, else a UInt8Array).

    When using ST_Color, pFormat tells the resulting format of the data, 'image/png' is by default. Available formats are the same as the HTMLCanvasElement.toDataURL() or HTMLCanvasElement.toBlob() calls. The API adds the 'image/raw' format to deal with individual pixels if requested (without image encoding). pQuality is a number in the [0,1] range, telling the expected quality if the requested format is a lossy compression scheme, such as 'image/jpeg'. If the requested format is not handled by the browser, 'image/png' type will be used.

    When using other formats, pFormat and pQuality are ignored.

    If pInBase64 is true, you may create a data url with the following code :

    /** 
    * Sample to illustrate the screenshot procedure of the InfiniteEngineInterface.
    */
    import {
    InfiniteEngineInterface, LoadingStates, Vector3, InfiniteEngineLoadingStateAttachment,
    InfiniteEngineInterfaceSignal, InfiniteEvent, InfiniteImageInterface, ScreenshotType
    } from 'generated/documentation/appinfiniteapi';

    // We try to make a screenshot when all data is loaded

    // the div to render the 3D display
    let lView3D: HTMLElement;

    // created previously, should receive the image data to be displayed to the user (or ask for a download maybe ?)
    let lImageData : HTMLImageElement;

    // created previously the position of the camera for the screenshot
    let lCameraLocation : Vector3;

    // created previously the camera center of interest
    let lCenterOfInterest : Vector3;

    // created previously the 3D engine
    let lInfiniteEngine: InfiniteEngineInterface;

    let lScreenshotId : string = '';
    // What to do when screenshot is ready ?
    let onScreenshotReady : (pEvent : InfiniteEvent, _pCallbackData) => void = undefined;

    // What to do when all data is loaded ?
    let onDataStateChanged : (pEvent : InfiniteEvent, _pCallbackData) => void = undefined;

    // bind the 3D rendering to the div (should have been done earlier :) )
    lInfiniteEngine.setView(lView3D);

    // we will make screenshot of 1024x1024
    lInfiniteEngine.setFixedResolution(1024, 1024, 1);

    lInfiniteEngine.addEventListener(InfiniteEngineInterfaceSignal.LoadingStateChanged, onDataStateChanged);
    lInfiniteEngine.addEventListener(InfiniteEngineInterfaceSignal.ScreenshotReady, onScreenshotReady);

    // go to the expected position / location
    lInfiniteEngine.getCameraManager().setCameraLocation(lCameraLocation);
    lInfiniteEngine.getCameraManager().lookAt(lCenterOfInterest, 0);

    // ####################################################################################################################################
    // ############################################ Screenshot ############################################################################
    // ####################################################################################################################################

    // What to do when state changes ? We wait till everything is loaded and then make a screenshot
    onDataStateChanged = (pEvent : InfiniteEvent, _pCallbackData) : void =>
    {
    // check the attachment
    const lStateAttachment : InfiniteEngineLoadingStateAttachment = pEvent.attachments;

    // some check, but useless, only for illustration purpose
    console.assert(lStateAttachment.newLoadingState === lInfiniteEngine.getResourceLoadingState());

    switch (lStateAttachment.newLoadingState)
    {
    case LoadingStates.S_Loading:
    // do nothing if we are still loading
    return;
    case LoadingStates.S_OutOfBudget:
    // some fancy message
    console.log('Taking a screenshot without everything loaded');
    // but we still make a screenshot :)
    break;
    default:
    break;
    }
    // make a screenshot request in jpeg with 95% quality, data will be base64 encoded
    lScreenshotId = lInfiniteEngine.screenshot(ScreenshotType.ST_Color, true, 'image/jpeg', 0.95);
    if (lScreenshotId.length === 0)
    {
    // for some reason, this failed
    console.log('Screenshot request failed');
    }
    }

    // what to do when we get the screenshot result ?
    onScreenshotReady = (pEvent : InfiniteEvent, _pCallbackData) : void =>
    {
    // the image result
    const lInfiniteImage : InfiniteImageInterface = pEvent.attachments;

    // if the id does not match, bail out
    if (lInfiniteImage.screenshotid !== lScreenshotId)
    {
    console.log('This is not the expected screenshot id, aborting')
    return;
    }

    // is the image valid ? and base64 encoded ?
    if ((lInfiniteImage.width === 0) || (!lInfiniteImage.data) || (!lInfiniteImage.base64))
    {
    console.log('Unexpected screenshot error, aborting')
    return;
    }

    // create the data url in base64
    // even if we did not get the expected format, we still get the result
    const lDataUrl : string = 'data:' + lInfiniteImage.format + ';base64,' + lInfiniteImage.data;

    // resize the image markup
    lImageData.width = lInfiniteImage.width;
    lImageData.height = lInfiniteImage.height;
    // and set data
    lImageData.src = lDataUrl;

    // we get back to the size of the 3d view but this is up to the application needs
    lInfiniteEngine.unsetFixedResolution();
    }

    Making a color screenshot.

    Returns

    A unique screenshot id request, or an empty string in case of error.

    See

    Parameters

    • pScreenshotType: ScreenshotType
      in
      The request screenshot type (image, geometric instance ids, etc).
    • pInBase64: boolean
      in
      If set to true, [data](InfiniteImageInterface.html#data) will be a base64 string.
    • Optional pFormat: string
      in
      The expected format of the resulting screenshot data ('image/png' by default).
    • Optional pQuality: number
      in
      The expected quality of the resulting screenshot data, in the [0,1] range in case of lossy compression formats.

    Returns string

  • Does nothing.

    Back-face culling is a rendering optimization that allows the 3d rendering to display the triangles only one-sided, this setup is now enforced by the DMU maintainer globally, or for individual geometries.

    Deprecated

    setBackfaceCullingEnabled will be removed in future release.

    Parameters

    • _pBackfaceCullingEnabled: boolean
      in
      Discarded.

    Returns void

  • Sets the background to be used in the rendering.

    The background of the rendering scene can be either a grid or a plain color. The grid is the default background. If pUseBackgroundColor is true the background shows the given color pBackgroundColor (R,G,B in the range [0,1]).

    Returns true if the background has been set. Setting pUseBackgroundColor to true without a valid color is invalid.

    Returns

    true if the background has been successfully set.

    Parameters

    • pUseBackgroundColor: boolean
      in
      If true shows the given pBackgroundColor else shows the ground and pBackgroundColor is ignored.
    • Optional pBackgroundColor: Vector3
      in
      Plain color used if the pShowBackground is set to false.

    Returns boolean

  • Sets the overridden rendering resolution of the rendering "window".

    If the HTMLElement set with the setView call ('HTMLViewElement') has not the same aspect ratio, then the 3d display is centered inside the given 'HTMLViewElement', showing the background color of the 'HTMLViewElement'.

    If the resolution is superior to the size of the 'HTMLViewElement', the rendering is scaled down to the available size.

    The 3D objects are rendered with ceil(pWidth) by ceil(pHeight) resolution, but you may want to have more precision on the displayed texts of annotations. For these reason, texts are rendered on an area of ceil(pWidth * pWindowRatio) by ceil(pHeight * pWindowRatio), allowing to have maximum performance on the 3D displayed objects and texts still readable.

    Screenshot request will have a resolution of ceil(pWidth * pWindowRatio) by ceil(pHeight * pWindowRatio).

    Returns

    true if the fixed resolution has been set and the 3 parameters are valid.

    Parameters

    • pWidth: number
      in
      The maximum number of horizontal pixels for the rendering window (valid values are > 0).
    • pHeight: number
      in
      The maximum number of vertical pixels for the rendering window (valid values are > 0).
    • pWindowRatio: number
      in
      The new window ratio for rendering texts (must be superior or equal to 1).

    Returns boolean

  • Sets the maximum resolution of the rendering "window".

    On some High DPI devices, the rendering size of the canvas may be too big to have a correct frame rate. You may choose to limit the maximum resolution to increase performance. The default maximum resolution is set to 1920 * 1080.

    Parameters

    • pWidth: number
      in
      The maximum number of horizontal pixels for the rendering window.
    • pHeight: number
      in
      The maximum number of vertical pixels for the rendering window.

    Returns void

  • Sets the HTML element to be used to render the DMU.

    Returns

    true if the 3D view is set.

    Parameters

    • pView: undefined | HTMLElement
      in
      The HTML element to render the DMU into.
    • Optional pForceEngineType: boolean | InfiniteEngineViewType
      in
      If set to true, then webgl1 rendering will be used, even if webgl2 is available. If set to an object, the rendering can be forced to webgl1 or webxr (see [InfiniteEngineViewType](InfiniteEngineViewType.html)). When requesting a webxr session, pView must be set to undefined.

    Returns boolean

  • Restores the rendering to use the HTMLElement set with the setView as the full display area.

    This function is the opposite to the setFixedResolution call.

    Returns void

  • Sets the visual state (Visible/hide/Ghost/Ignore cut plane) of geometric instance ids.

    The visual state is a bit field that allows to change a lot of geometric instance ids at once.

    The bit mask is used to tell which bits will be changed by the function call (the use may want to preserve the ghost state of the geometric instances for example).

    The bit value tells the value to set (bits not set by the mask will not be altered).

    /** 
    * Sample to illustrate how to change the visibility of a set of `geometric instances`.
    */
    import { InfiniteEngineInterface, VisualStates } from 'generated/documentation/appinfiniteapi';

    // created previously
    let lInfiniteEngine : InfiniteEngineInterface;

    // 8 bits for visibility
    // sets all instances visible and not ghosted (do not care about "x" values)
    // Mask => xxxx 1101
    //
    // not ghosted => xxxx x0xx
    // not hidden (visible) => xxxx 0xx0
    // we want to set => xxxx 00x0
    // we can use 0 for values !!!!
    lInfiniteEngine.updateGeometricStateForAll(VisualStates.S_Ghost | VisualStates.S_Hidden, 0);

    // sets 2 instances hidden, but clear the ghost for them, and clear selection
    // Mask => xxxx 1111
    //
    // not ghosted => xxxx x0xx
    // hidden => xxxx 1xx1
    // not selected => xxxx xx0x
    // we want to set => xxxx 1001
    // we can use VisualStates.S_Hidden for values !!!!
    const lCurrentGeometries : Uint32Array = new Uint32Array(2);
    lCurrentGeometries[0] = 57;
    lCurrentGeometries[1] = 64;
    lInfiniteEngine.updateGeometricState(lCurrentGeometries, VisualStates.S_Ghost | VisualStates.S_Hidden | VisualStates.S_Selected, VisualStates.S_Hidden);

    Please refer to the [VisualStates](../enums/VisualStates.html) for a list of possible values.

    See

    VisualStates

    Parameters

    • pGeometricIds: number[] | Uint32Array
      in
      The geometric instance ids that will be changed by the function call.
    • pBitMask: number
      in
      The bit mask ("ORed" value of the [VisualStates](../enums/VisualStates.html)) of the states that will be altered.
    • pBitValue: number
      in
      The bit value ("ORed" value of the [VisualStates](../enums/VisualStates.html)) of the states that will be set.

    Returns void

  • Sets the visual state (Visible/hide/Ghost/Ignore cut plane) of all the geometric instances.

    The visual state is a bit field that allows to change a lot of geometric instance ids at once.

    The bit mask is used to tell which bits will be changed by the function call (the use may want to preserve the ghost state of the geometric instances for example).

    The bit value tells the value to set (bits not set by the mask will not be altered).

    /** 
    * Sample to illustrate how to change the visibility of a set of `geometric instances`.
    */
    import { InfiniteEngineInterface, VisualStates } from 'generated/documentation/appinfiniteapi';

    // created previously
    let lInfiniteEngine : InfiniteEngineInterface;

    // 8 bits for visibility
    // sets all instances visible and not ghosted (do not care about "x" values)
    // Mask => xxxx 1101
    //
    // not ghosted => xxxx x0xx
    // not hidden (visible) => xxxx 0xx0
    // we want to set => xxxx 00x0
    // we can use 0 for values !!!!
    lInfiniteEngine.updateGeometricStateForAll(VisualStates.S_Ghost | VisualStates.S_Hidden, 0);

    // sets 2 instances hidden, but clear the ghost for them, and clear selection
    // Mask => xxxx 1111
    //
    // not ghosted => xxxx x0xx
    // hidden => xxxx 1xx1
    // not selected => xxxx xx0x
    // we want to set => xxxx 1001
    // we can use VisualStates.S_Hidden for values !!!!
    const lCurrentGeometries : Uint32Array = new Uint32Array(2);
    lCurrentGeometries[0] = 57;
    lCurrentGeometries[1] = 64;
    lInfiniteEngine.updateGeometricState(lCurrentGeometries, VisualStates.S_Ghost | VisualStates.S_Hidden | VisualStates.S_Selected, VisualStates.S_Hidden);

    Please refer to the [VisualStates](../enums/VisualStates.html) for a list of possible values.

    See

    VisualStates

    Parameters

    • pBitMask: number
      in
      The bit mask ("ORed" value of the [VisualStates](../enums/VisualStates.html)) of the states that will be altered.
    • pBitValue: number
      in
      The bit value ("ORed" value of the [VisualStates](../enums/VisualStates.html)) of the states that will be set.

    Returns void