Interface InfiniteEngineInterface

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

The usage is very basic :

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

WARNING : There is no automatic conversion of the content of WorkingSetInterface 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 by an InfiniteFactory.
The InfiniteEngineInterface is connected to a DataSessionInterface with InfiniteEngineInterface.bindDataSession or DataSessionInterface.bindInfiniteEngine. 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, tListenerCallback, DataSessionInterface } from 'generated_files/documentation/appinfiniteapi';

// the callback when a pick request is completed
let onPicking : tListenerCallback;
// the Data session, created previously
let lDataSession : DataSessionInterface;

// create an Infinite engine
const lInfiniteEngine : InfiniteEngineInterface = InfiniteFactory.CreateInfiniteEngine();
// bind the data session and the Infinite engine
lDataSession.bindInfiniteEngine(lInfiniteEngine);

// get the html element that will host the 3d rendering
const lView3D: 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 InfiniteEnginePerformanceInterface 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 { InfiniteEngineInterface, InfiniteEnginePerformanceInterface } from 'generated_files/documentation/appinfiniteapi';

// created previously
let lInfiniteEngine : InfiniteEngineInterface;
// get the performance interface
const lPerformanceInfos : InfiniteEnginePerformanceInterface = lInfiniteEngine.getPerformance();

// reset the number of triangles to display in the dynamic low definition DMU
lPerformanceInfos.setMaxDynamicLowDefTrianglesDisplayedCount(lPerformanceInfos.GetMaxDynamicLowDefTrianglesDefault());
// reset the number of total triangles to be displayed
lPerformanceInfos.setMaxTrianglesDisplayedCount(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 and the LoadingStates enumeration.
 /** 
* Sample to illustrate getting the loading state (updating, ok, out of budget) of the InfiniteEngineInterface.
*/
import { InfiniteEngineInterface, LoadingStates } from 'generated_files/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 may be included in the DataSessionInterface 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 color, depending on the current object color.
  • 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_files/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 accessed through getMaterialManager. The MaterialManagerInterface 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, `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_files/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.getOriginalMaterialsOfInstanceCount(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 += 1;
}
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.

2 rendering modes are available : a default one with some default lights, rendering is done accounting for the primitives normal, and a 'flat' one, where lights and normal are ignored, displaying only the material color of the geometries. Changing the rendering mode is done through setRenderingMode.

available rendering modes

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 pick result will tell the :

  • 3D geometry
  • Annotation
  • Primitive line
  • Primitive box
  • Primitive line That is under the given pixel.
    If you request to pick only the closest item, then only the closest 3D geometry, Annotation, Primitive will be included in the result : e.g. if the 3D geometry is the closest item to the camera, then only the given id will be included in the picking result, discarding any primitive / annotation that may also be under the given pixel.

The picking is asynchronous, meaning a InfiniteEngineInterfaceSignal.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 InfiniteEngineInterface.pickAt without waiting for the result will trigger multiple InfiniteEngineInterfaceSignal.Picked events, they can be distinguished with their picking request ids (InfiniteEngineInterface.getLastPickingRequestId and PickingAttachment.pickingRequestId).
Geometric instances, lines, boxes, and points are queried at the same time on a single pick request (see PrimitiveManagerLineInterface, PrimitiveManagerBoxInterface, PrimitiveManagerPointInterface). The computePickRay and projectToScreen functions may be used with the pick functions to make some more 3D calculations. You may pick a single point (InfiniteEngineInterface.pickAt), a rectangular area (InfiniteEngineInterface.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, PickingAttachment, PickingAttachmentItem,
Vector3, VisualStates, InfiniteEngineInterfaceSignal, Rectangle, InfiniteEvent,
PrimitiveManagerInterface
} from 'generated_files/documentation/appinfiniteapi';

// the div to render to
let lView3D: HTMLElement;

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

// 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 += 1) {
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, false);
}
else
{
// pick an area
lInfiniteEngine.pickRect(lRubberBand, false);
}
// 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, PickingAttachment, PickingAttachmentItem, Vector3, VisualStates, AsyncPickingResult,
Rectangle, AsyncResultReason, PrimitiveManagerInterface,
} from 'generated_files/documentation/appinfiniteapi';

// the div to render to
let lView3D: HTMLElement;

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

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

// We pick a rectangle if big enough, else only a point
let pickAtImpl : () => Promise<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 += 1) {
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<void> =>
{
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, false);
}
else
{
// pick an area
lPickingResult = await lInfiniteEngine.asyncPickRect(lRubberBand, false);
}
// 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 InfiniteEngineInterfaceSignal.ScreenshotReady event is fired when the screenshot is ready. The screenshot call returns an id, and this is must match the attachment of the InfiniteEngineInterfaceSignal.ScreenshotReady event which is an InfiniteImageInterface (InfiniteImageInterface.screenshotid). An empty string means the screenshot procedure has failed (a missing setView call probably). An empty InfiniteImageInterface.width or InfiniteImageInterface.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_files/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_files/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. Multiple behaviors are available, e.g. orbital ones, when the camera moves around a center of interest.

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 CutPlaneManagerInterface.createCutPlaneManipulator.

Object with a visual state VisualStates.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_files/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.

Transformations.

You may change the matrix of a set of parts. If you want to compose some matrix on top of the existing one, just use InfiniteEngineInterface.addMatrix. You may also override the full matrix of a given piece with InfiniteEngineInterface.setMatrix.

/** 
* Sample to illustrate how to change the matrix of a set of `geometric instances`.
*/
import { DataSessionInterface, InfiniteEngineInterface, Matrix4, Unit, Vector3 } from 'generated_files/documentation/appinfiniteapi';

// created previously
let lInfiniteEngine : InfiniteEngineInterface;
// created previously
let lDataSession : DataSessionInterface;

// the geometric instance ids to translate
let lCurrentGeometries : Uint32Array;

// the resulting transformation
const lTransformMatrix : Matrix4 = new Matrix4();
// we will translate 1 meter
const lOneMeter : number = 1 * lDataSession.convertUnitFactor(Unit.U_Meter, lDataSession.getDmuBuildUnit());

// we will want to translate the given pieces of 1 meter in the up direction
const lZVector : Vector3 = new Vector3();
lInfiniteEngine.getCameraManager().getFrameReference(undefined, lZVector);
lZVector.scale(lOneMeter);

// set this as the translation
lTransformMatrix.setTranslationPart(lZVector.x, lZVector.y, lZVector.z);
// and translate the given part with this value
lInfiniteEngine.addMatrix(lCurrentGeometries, lTransformMatrix);

Setting transforms.

You may also 'explode' geometries in one or multiple directions, objects are translated depending on the distance between the center of the explosion and the center of each object.

engine explosion upon x axis
/** 
* Sample to illustrate how to set an explosion for a set of `geometric instances`.
*/
import { InfiniteEngineInterface, Matrix4, Vector3 } from 'generated_files/documentation/appinfiniteapi';

// created previously
let lInfiniteEngine : InfiniteEngineInterface;

// the geometric instance ids to translate
let lCurrentGeometries : Uint32Array;

// the direction we want the transform to apply
// created previously
let lExplodedDirection : Vector3;

// the center of the explosion
// created previously
let lExplosionCenter : Vector3;

// other directions
const lOtherDirections : Array<Vector3> = [new Vector3(1, 0, 0), new Vector3()];

// normalize the vector, just in case, but it may be useless
lExplodedDirection.normalize();

// create a new unit frame with lExplodedDirection
lExplodedDirection.crossVector(lOtherDirections[0], lOtherDirections[1]);
if(lOtherDirections[1].lengthSquare() === 0)
{
// lExplodedDirection is colinear to 1, 0, 0 ?
lOtherDirections[0].set(0, 1, 0);
lExplodedDirection.crossVector(lOtherDirections[0], lOtherDirections[1]);
}
lOtherDirections[1].normalize();
lOtherDirections[1].crossVector(lExplodedDirection, lOtherDirections[0]);
// this should not be necessary
lOtherDirections[0].normalize();

// now we have a direct orthonormal frame with lExplodedDirection, lOtherDirections[0], lOtherDirections[1]

// we will explode distances upon lExplodedDirection multiplying distance by 2
const lScaleFactor : number = 2;

const lScaleMatrix : Matrix4 = new Matrix4();
lScaleMatrix.makeIdentity();
lScaleMatrix.array[0] = lScaleFactor;

// the rotation matrix from the current frame to the new frame [lExplodedDirection, lOtherDirections[0], lOtherDirections[1]]
const lRotationMatrix : Matrix4 = new Matrix4();
lRotationMatrix.set(lExplodedDirection.x, lExplodedDirection.y, lExplodedDirection.z, 0, lOtherDirections[0].x, lOtherDirections[0].y, lOtherDirections[0].z, 0, lOtherDirections[1].x, lOtherDirections[1].y, lOtherDirections[1].z, 0, 0, 0, 0, 1);
// the inverse rotation matrix => transpose
const lInverseRotationMatrix : Matrix4 = new Matrix4();
lInverseRotationMatrix.set(lExplodedDirection.x, lOtherDirections[0].x, lOtherDirections[1].x, 0, lExplodedDirection.y, lOtherDirections[0].y, lOtherDirections[1].y, lExplodedDirection.z, lOtherDirections[0].z, 0, lOtherDirections[1].z, 0, 0, 0, 0, 1);

lScaleMatrix.multiplyMatrixLeft(lRotationMatrix);
lScaleMatrix.multiplyMatrixRight(lInverseRotationMatrix);
// lScaleMatrix now holds the explosion in the given specific direction.

// and explode the geometries
lInfiniteEngine.addExplodedInstances(lCurrentGeometries, lExplosionCenter, lScaleMatrix);

Setting 'explosions'.

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. Annotations rendering are available through InfiniteEngineInterface.getAnnotationRenderer.

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 PrimitiveManagerInterface.getPrimitiveMaterialManager. 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_files/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().getPrimitiveMaterialManager();
// 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.createPrimitiveMaterial(lInnerPointColor);
lOuterPointColorMaterial = lPrimitiveMaterialManager.createPrimitiveMaterial(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_files/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().getPrimitiveMaterialManager();
// 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.createPrimitiveMaterial(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_files/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().getPrimitiveMaterialManager();
// 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.createPrimitiveMaterial(lFaceColor);
lEdgeColorMaterial = lPrimitiveMaterialManager.createPrimitiveMaterial(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_files/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_files/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.
3D Rendering

interface InfiniteEngineInterface {
    addEventListener(pType, pListener, pObject): string;
    addEventListener(pType, pListener): string;
    addExplodedInstances(pGeometricInstanceIds, pReferencePoint, pScaleMatrix): boolean;
    addMatrix(pGeometricInstanceIds, pMatrix): boolean;
    arePatchBordersEnabled(): boolean;
    areSignalsBlocked(): boolean;
    asyncPickAt(pX, pY, pPickOnlyClosest): Promise<AsyncPickingResult>;
    asyncPickFromRay(pOrigin, pDirection, pPickOnlyClosest): Promise<AsyncPickingResult>;
    asyncPickRect(pRectangle, pPickOnlyClosest): Promise<AsyncPickingResult>;
    asyncScreenshot(pScreenshotType, pInBase64, pFormat?, pQuality?): Promise<AsyncScreenshotResult>;
    asyncWaitForDataLoaded(pTimeoutInMilliseconds?): Promise<AsyncDataLoadedResult>;
    asyncWaitForDataSessionLoaded(pDataSession?): Promise<AsyncResultReason>;
    bindDataSession(pDataSession): boolean;
    blockSignals(pBlock): void;
    computePickRay(pX, pY, pPickRayOut, pOrigin): boolean;
    dispose(): void;
    enableAntiAliasing(pEnable): boolean;
    enableCopyrightedWatermark(pEnabled): boolean;
    enableEdgeDetect(pEnable): boolean;
    enablePatchBorders(pEnable): boolean;
    fromJSON(pEngineData): boolean;
    getAnnotationRenderer(): AnnotationRendererInterface;
    getBackground(pBackgroundColor): boolean;
    getBindSessionProgress(): number;
    getBoundDataSession(): DataSessionInterface;
    getCameraManager(): CameraManagerInterface;
    getCurrentGeometricAABB(pGeometricInstanceId, pAABBOut): boolean;
    getCurrentGeometricMatrix(pGeometricInstanceId, pMatrixOut): boolean;
    getCurrentUnitedAABB(pGeometricInstanceIds, pAABBOut): boolean;
    getCutPlaneManager(): CutPlaneManagerInterface;
    getDefaultHardwareInstancingUsage(): boolean;
    getDefaultVertexArrayObjectsUsage(): boolean;
    getFeatureManager(): FeatureManagerInterface;
    getFixedResolution(pResolution): boolean;
    getGeometricState(pGeometricId): number;
    getInfiniteObjectType(): InfiniteObjectType;
    getLastPickingRequestId(): string;
    getMaterialManager(): MaterialManagerInterface;
    getPerformance(): InfiniteEnginePerformanceInterface;
    getPrimitiveManager(): PrimitiveManagerInterface;
    getRenderingMode(): RenderingMode;
    getResourceLoadingProgress(): number;
    getResourceLoadingState(): LoadingStates;
    getTransformedInstances(pInstances): boolean;
    getView(): HTMLElement;
    getVisualAABB(pBitMask, pBitValue, pAABB): boolean;
    getWebGLRenderingContext(): WebGLRenderingContext;
    getXRFrame(): any;
    getXRSession(): any;
    hasEventListener(pType, pListener): boolean;
    hasEventListenerById(pId): boolean;
    isAntiAliasingEnabled(): boolean;
    isCopyrightedWatermarkEnabled(): boolean;
    isDisposed(): boolean;
    isEdgeDetectEnabled(): boolean;
    isLoaded(): boolean;
    isRendererIdle(): boolean;
    isUsingHardwareInstancing(): boolean;
    isUsingVertexArrayObjects(): boolean;
    pickAt(pX, pY, pPickOnlyClosest): boolean;
    pickFromRay(pOrigin, pDirection, pPickOnlyClosest): boolean;
    pickRect(pRectangle, pPickOnlyClosest): boolean;
    projectToScreen(pPoint, pScreenCoordinatesOut): boolean;
    removeAllEventListeners(): boolean;
    removeEventListener(pType, pListener, pObject): boolean;
    removeEventListener(pType, pListener): boolean;
    removeEventListenerById(pId): boolean;
    restoreAllOriginalMatrices(): void;
    restoreOriginalMatrix(pGeometricInstanceIds): boolean;
    screenshot(pScreenshotType, pInBase64, pFormat?, pQuality?): string;
    setAntiAliasingEnabled(pEnable): boolean;
    setBackground(pUseBackgroundColor, pBackgroundColor?): boolean;
    setCopyrightedWatermarkEnabled(pEnabled): boolean;
    setDefaultHardwareInstancingUsage(pEnable): void;
    setDefaultVertexArrayObjectsUsage(pEnable): void;
    setEdgeDetectEnabled(pEnable): boolean;
    setFixedResolution(pWidth, pHeight, pWindowRatio): boolean;
    setMatrix(pGeometricInstanceIds, pMatrix): boolean;
    setMaximumEngineResolution(pWidth, pHeight): boolean;
    setPatchBordersEnabled(pEnable): boolean;
    setRenderingMode(pRenderingMode): boolean;
    setView(pView, pForceEngineType?): boolean;
    toJSON(pKey?): Object;
    unsetFixedResolution(): void;
    updateGeometricState(pGeometricIds, pBitMask, pBitValue): boolean;
    updateGeometricStateForAll(pBitMask, pBitValue): boolean;
}

Hierarchy (view full)

Methods

addEventListener addExplodedInstances addMatrix arePatchBordersEnabled areSignalsBlocked asyncPickAt asyncPickFromRay asyncPickRect asyncScreenshot asyncWaitForDataLoaded asyncWaitForDataSessionLoaded bindDataSession blockSignals computePickRay dispose enableAntiAliasing enableCopyrightedWatermark enableEdgeDetect enablePatchBorders fromJSON getAnnotationRenderer getBackground getBindSessionProgress getBoundDataSession getCameraManager getCurrentGeometricAABB getCurrentGeometricMatrix getCurrentUnitedAABB getCutPlaneManager getDefaultHardwareInstancingUsage getDefaultVertexArrayObjectsUsage getFeatureManager getFixedResolution getGeometricState getInfiniteObjectType getLastPickingRequestId getMaterialManager getPerformance getPrimitiveManager getRenderingMode getResourceLoadingProgress getResourceLoadingState getTransformedInstances getView getVisualAABB getWebGLRenderingContext getXRFrame getXRSession hasEventListener hasEventListenerById isAntiAliasingEnabled isCopyrightedWatermarkEnabled isDisposed isEdgeDetectEnabled isLoaded isRendererIdle isUsingHardwareInstancing isUsingVertexArrayObjects pickAt pickFromRay pickRect projectToScreen removeAllEventListeners removeEventListener removeEventListenerById restoreAllOriginalMatrices restoreOriginalMatrix screenshot setAntiAliasingEnabled setBackground setCopyrightedWatermarkEnabled setDefaultHardwareInstancingUsage setDefaultVertexArrayObjectsUsage setEdgeDetectEnabled setFixedResolution setMatrix setMaximumEngineResolution setPatchBordersEnabled setRenderingMode setView toJSON unsetFixedResolution updateGeometricState updateGeometricStateForAll

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. Calling twice addEventListener with the same parameters results in the second call to be ignored, only unique pairs callback / object are allowed, in order to avoid calling multiple times the same thing.

    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: Object
      in
      The optional object the callback will be called with when the given event fires.

    Returns string

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

  • 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.

    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

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

  • 'Explodes' the given geometric instances with the given scale.

    The transform will be applied to the current position of the given geometric instances.

    The explosion algorithm is simple, the center of each geometric instance is translated by an amount depending on the current distance between the center and a given point (center of the 'explosion').

    Returns true if at least one geometric instance id inside pGeometricInstanceIds is valid and thus modified. Returns false if pScaleMatrix is identity. Floating point numbers are considered invalid, and numbers outside the range of valid geometric instance ids are silently discarded (such numbers are not considered invalid, they are just discarded). Invalid geometric instance ids are also values that are not numbers. Invalid geometric instance ids are discarded, and if all values are discarded, the function returns false.

    You may want to :

    • Compute the explosion of the x axis : pScaleMatrix.set(scale, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
    • Compute the explosion of the y axis : pScaleMatrix.set(1, 0, 0, 0, 0, scale, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1);
    • Compute the explosion on a specific frame : R1, R2, R3 (R1 and R2 orthogonal, R2 and R3 orthogonal), on axis R1:
      • pRotationMatrix.set(R1.x, R1.y, R1.z, 0, R2.x, R2.y, R2.z, 0, R3.x, R3.y, R3.z, 0, 0, 0, 0, 1).
        • pInverseRotationMatrix.set(R1.x, R2.x, R3.x, 0, R1.y, R2.y, R3.y, R1.z, R2.z, 0, R3.z, 0, 0, 0, 0, 1).
      • pUnitScaleMatrix.set(scale, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1).
      • pRotationMatrix.multiplyMatrixRight(pUnitScaleMatrix, pScaleMatrix).
      • pScaleMatrix.multiplyMatrixRight(pInverseRotationMatrix)
      • pScaleMatrix now holds the explosion in the given specific direction.

    Parameters

    • pGeometricInstanceIds: number | number[] | Uint32Array
      in
      the list of geometric instance ids to query.
    • pReferencePoint: Vector3
      in
      The reference point from which computing the 'explosion'.
    • pScaleMatrix: Matrix4
      in
      The scale to set for each direction.

    Returns boolean

    true if at least one geometric instance id inside pGeometricInstanceIds is modified and if pMatrix is not identity.

  • Transforms the given geometric instances by the given matrix.

    The transform will be applied to the current position of the given geometric instances.

    Returns true if at least one geometric instance id inside pGeometricInstanceIds is valid and thus modified. Returns false if pMatrix is identity. Floating point numbers are considered invalid, and numbers outside the range of valid geometric instance ids are silently discarded (such numbers are not considered invalid, they are just discarded). Invalid geometric instance ids are also values that are not numbers. Invalid geometric instance ids are discarded, and if all values are discarded, the function returns false.

    Parameters

    • pGeometricInstanceIds: number | number[] | Uint32Array
      in
      the list of geometric instance ids to query.
    • pMatrix: Matrix4
      in
      the transformation to add to the current geometry position.

    Returns boolean

    true if at least one geometric instance id inside pGeometricInstanceIds is modified and if pMatrix is not identity.

  • Tells if the patch borders rendering mechanism is enabled.

    Returns boolean

    true if patch borders rendering is enabled.

  • Tells if signals sent by the object are blocked or not.

    If signals are blocked, no signal will be emitted nor buffered, such signal will be lost.

    Returns boolean

    true if signals are blocked.

  • 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.

    If pPickOnlyClosest is true, then only the closest item under the picked point will be included, discarding other types of data if relevant.

    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).
    • pPickOnlyClosest: boolean
      in
      If set, only closest items will be retrieved.

    Returns Promise<AsyncPickingResult>

    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.

  • 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 InfiniteEngineInterfaceSignal.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.

    If pPickOnlyClosest is true, then only the closest item under the picked ray will be included, discarding other types of data if relevant.

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

    // the div to render to
    let lView3D: HTMLElement;

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

    // We pick a rectangle if big enough, else only a point
    let pickAtImpl : () => Promise<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 += 1) {
    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<void> =>
    {
    const lPickingResult : AsyncPickingResult = await lInfiniteEngine.asyncPickFromRay(lPickRayOrigin, lPickRayDirection, false);
    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.

    Parameters

    • pOrigin: Vector3
      in
      The origin of the ray.
    • pDirection: Vector3
      in
      The direction of the ray.
    • pPickOnlyClosest: boolean
      in
      If set, only closest items will be retrieved.

    Returns Promise<AsyncPickingResult>

    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.

  • 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.

    If pPickOnlyClosest is true, then only the closest items under the picked rectangle will be included, discarding other types of data if relevant.

    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).
    • pPickOnlyClosest: boolean
      in
      If set, only closest items will be retrieved.

    Returns Promise<AsyncPickingResult>

    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.

  • 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 (InfiniteImageInterface.data will be a string, else a UInt8Array).

    When using ScreenshotType.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_files/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.

    Parameters

    • pScreenshotType: ScreenshotType
      in
      The request screenshot type (image, geometric instance ids, etc).
    • pInBase64: boolean
      in
      If set to true, InfiniteImageInterface.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>

    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.

  • Requests an asynchronous wait for data loaded.

    The promise is signaled when the data loading process is over, i.e. when getResourceLoadingState returns LoadingStates.S_AllLoaded or LoadingStates.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_files/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.

    Parameters

    • Optional pTimeoutInMilliseconds: number
      in
      If strictly positive, the wait will not be more than pTimeoutInMilliseconds milliseconds.

    Returns Promise<AsyncDataLoadedResult>

    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.

  • Requests an asynchronous wait for the bound data session (DataSessionInterface) to be loaded.

    If pDataSession is undefined, then the call waits for the currently bound DataSessionInterface to be loaded. If pDataSession is set, this call sets the given DataSessionInterface with bindDataSession and waits for it to be loaded in this InfiniteEngineInterface.

    The promise is signaled when the InfiniteEngineInterface has finished loading data from the currently bound DataSessionInterface.

    If the InfiniteEngineInterface is bound to another DataSessionInterface during the call or if the InfiniteEngineInterface is disposed, then the Promise is signalled with an error. If the InfiniteEngineInterface is already loaded, the promise is signalled right away.

    Returns a Promise telling if the InfiniteEngineInterface has finished loading resources from the DataSessionInterface.

    Parameters

    Returns Promise<AsyncResultReason>

    A promise. The promise is resolved with the reason (success, cancelled, disposed, bad input).

  • Blocks / Unblocks all signals sent by the object.

    If signals are blocked, no signal will be emitted nor buffered, such signal will be lost.

    Parameters

    • pBlock: boolean
      in
      If set to true, all further signals will be silently discarded.

    Returns void

  • 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 computePickRay(0,0,lDir0,lCamPos), computePickRay(0,1,lDir1,lCamPos), computePickRay(1,0,lDir2,lCamPos), computePickRay(1,0,lDir3,lCamPos) effectively stores the limiting rays of the view frustum.

    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

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

  • Enables / disables anti aliasing.

    Anti aliasing is disabled by default.

    This is the same call as setAntiAliasingEnabled.

    Parameters

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

    Returns boolean

    true is the call succeeded.

  • 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.

    This is the same call as setCopyrightedWatermarkEnabled.

    Parameters

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

    Returns boolean

    true if the call succeeded.

  • Enables / disables edge detection mechanism.

    Edge detection is disabled by default.

    This is the same call as setEdgeDetectEnabled.

    Parameters

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

    Returns boolean

    true if the call succeeded.

  • Enables / disables patch borders mechanism.

    Patch borders are disabled by default.

    patch borders rendering
    This is the same call as setPatchBordersEnabled.

    Parameters

    • pEnable: boolean
      in
      If set, enables the patch borders rendering mechanism.

    Returns boolean

    true if the call succeeded.

  • Sets the content of the InfiniteEngineInterface from a former call to toJSON.

    InfiniteEngineInterface parameters (Cut-planes and camera definitions) may be streamed, using the following schema :

    {
    "$defs": {
    "camera": {
    "additionalProperties": false,
    "description": "Define the values of a Camera",
    "properties": {
    "coi": {
    "$ref": "#/$defs/vec3"
    },
    "dvector": {
    "$ref": "#/$defs/vec3"
    },
    "frontdir": {
    "$ref": "#/$defs/vec3"
    },
    "location": {
    "$ref": "#/$defs/vec3"
    },
    "projection": {
    "$ref": "#/$defs/cameraprojection"
    },
    "rvector": {
    "$ref": "#/$defs/vec3"
    },
    "topdir": {
    "$ref": "#/$defs/vec3"
    },
    "uvector": {
    "$ref": "#/$defs/vec3"
    }
    },
    "required": [
    "location",
    "dvector",
    "uvector",
    "rvector",
    "coi",
    "frontdir",
    "topdir",
    "projection"
    ],
    "title": "Camera definition",
    "type": "object"
    },
    "cameracontroller": {
    "additionalProperties": false,
    "description": "Define the values of a Camera controller",
    "properties": {
    "camera": {
    "$ref": "#/$defs/camera"
    },
    "currentcameramode": {
    "$ref": "#/$defs/cameramode"
    },
    "fly": {
    "$ref": "#/$defs/flymode"
    },
    "orbit": {
    "$ref": "#/$defs/orbitmode"
    },
    "version": {
    "description": "Define the version of the object",
    "example": 1,
    "type": "integer"
    }
    },
    "required": [],
    "title": "Camera controller definition",
    "type": "object"
    },
    "cameramode": {
    "enum": [
    "orbit",
    "examine",
    "none",
    "fly"
    ],
    "type": "string"
    },
    "cameraprojection": {
    "additionalProperties": false,
    "properties": {
    "horizontal": {
    "type": "boolean"
    },
    "isperspective": {
    "type": "boolean"
    },
    "projectionvalue": {
    "exclusiveMinimum": 0,
    "type": "number"
    }
    },
    "required": [
    "isperspective",
    "projectionvalue"
    ],
    "title": "Camera projection definition",
    "type": "object"
    },
    "cutplane": {
    "additionalProperties": false,
    "properties": {
    "enabled": {
    "default": true,
    "description": "If disabled, this filter is completely ignored during all the computations",
    "example": true,
    "type": "boolean"
    },
    "group": {
    "default": 0,
    "description": "Cut planes may be grouped together. In that case, an area is considered 'cut' if ALL cut planes cut this area.",
    "example": 0,
    "maximum": 7,
    "minimum": 0,
    "type": "integer"
    },
    "normal": {
    "$ref": "#/$defs/vec3"
    },
    "point": {
    "$ref": "#/$defs/vec3"
    }
    },
    "required": [
    "enabled",
    "point",
    "normal"
    ],
    "title": "Cut plane definition",
    "type": "object"
    },
    "cutplanes": {
    "additionalProperties": false,
    "properties": {
    "cutplanes": {
    "items": {
    "$ref": "#/$defs/cutplane"
    },
    "type": "array"
    },
    "type": {
    "const": "cutplanes",
    "type": "string"
    },
    "version": {
    "description": "Define the version of the object",
    "example": 1,
    "type": "integer"
    }
    },
    "required": [
    "type",
    "cutplanes"
    ],
    "title": "Cut planes definition",
    "type": "object"
    },
    "flymode": {
    "additionalProperties": false,
    "properties": {
    "heightlocked": {
    "type": "boolean"
    },
    "keymapping": {
    "$ref": "#/$defs/flymode_keymapping"
    },
    "rotationspeed": {
    "exclusiveMinimum": 0,
    "type": "number"
    },
    "translationspeed": {
    "exclusiveMinimum": 0,
    "type": "number"
    }
    },
    "required": [],
    "title": "Fly mode definition",
    "type": "object"
    },
    "flymode_keymapping": {
    "additionalProperties": false,
    "properties": {
    "backward": {
    "default": "KeyS",
    "type": "string"
    },
    "down": {
    "default": "KeyF",
    "type": "string"
    },
    "forward": {
    "default": "KeyW",
    "type": "string"
    },
    "left": {
    "default": "KeyA",
    "type": "string"
    },
    "right": {
    "default": "KeyD",
    "type": "string"
    },
    "shift": {
    "default": "ShiftLeft",
    "type": "string"
    },
    "up": {
    "default": "KeyR",
    "type": "string"
    },
    "version": {
    "description": "Define the version of the object",
    "example": 1,
    "type": "integer"
    }
    },
    "required": [],
    "title": "Fly mode key mapping definition",
    "type": "object"
    },
    "orbitmode": {
    "additionalProperties": false,
    "properties": {
    "controllersensitivity": {
    "exclusiveMinimum": 0,
    "type": "number"
    },
    "upconstraint": {
    "type": "boolean"
    }
    },
    "required": [],
    "title": "Orbit mode definition",
    "type": "object"
    },
    "renderingcontext": {
    "additionalProperties": false,
    "properties": {
    "cameracontrollerdefinition": {
    "$ref": "#/$defs/cameracontroller"
    },
    "cutplanesdefinition": {
    "$ref": "#/$defs/cutplanes"
    },
    "rendering": {
    "$ref": "#/$defs/renderingproperties"
    },
    "type": {
    "const": "renderingcontext",
    "description": "Type of context",
    "type": "string"
    },
    "version": {
    "description": "Define the version of the object",
    "example": 1,
    "type": "integer"
    }
    },
    "required": [
    "type",
    "version"
    ],
    "type": "object"
    },
    "renderingmode": {
    "enum": [
    "default",
    "flat_shading"
    ],
    "type": "string"
    },
    "renderingproperties": {
    "additionalProperties": false,
    "properties": {
    "antialiasing": {
    "type": "boolean"
    },
    "background": {
    "maxLength": 9,
    "pattern": "^#[0-9a-fA-F]{8}|ground$",
    "type": "string"
    },
    "edgedetect": {
    "type": "boolean"
    },
    "patchborders": {
    "type": "boolean"
    },
    "renderingmode": {
    "$ref": "#/$defs/renderingmode"
    },
    "type": {
    "const": "renderingproperties",
    "type": "string"
    },
    "version": {
    "description": "Define the version of the object",
    "example": 1,
    "type": "integer"
    }
    },
    "required": [
    "type"
    ],
    "type": "object"
    },
    "vec3": {
    "description": "Define the coordinates [x,y,z] of a point / vector",
    "items": {
    "type": "number"
    },
    "maxItems": 3,
    "minItems": 3,
    "title": "3D Vector definition",
    "type": "array"
    }
    },
    "$ref": "#/$defs/renderingcontext",
    "$schema": "https://json-schema.org/draft-07/schema#"
    }

    This schema may evolve in the future.

    Parameters

    • pEngineData: string | Object
      in
      Internal InfiniteEngineInterface data to set.

    Returns boolean

    true if the data is set.

  • 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.

    Parameters

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

    Returns boolean

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

  • Gets the current axis aligned bounding box of the given geometric instance id.

    This returns the AABB that may be transformed of the given geometric instance id has been moved.

    Returns true if the given geometric instance id is valid.

    Parameters

    • pGeometricInstanceId: number
      in
      The geometric instance id to query.
    • pAABBOut: AABB
      out
      The resulting AABB of the geometric instance.

    Returns boolean

    true if pAABBOut is updated.

  • Gets the matrix of the given geometric instance id.

    This may included the transformation set by addMatrix, setMatrix.

    Returns true if the given geometric instance id is valid.

    Parameters

    • pGeometricInstanceId: number
      in
      The geometric instance id to query.
    • pMatrixOut: Matrix4
      out
      The resulting Matrix of the geometric instance.

    Returns boolean

    true if pMatrixOut is updated.

  • Computes the current axis aligned bounding box of the given geometric instances.

    This consists in the union of all the AABB of the geometric instances expressed by their geometric instance ids.

    Returns true if at least one geometric instance id inside pGeometricInstanceIds is valid. Invalid geometric instance ids are silently discarded.

    Parameters

    • pGeometricInstanceIds: number[] | Uint32Array
      in
      the list of geometric instance ids to query.
    • pAABBOut: AABB
      out
      the union of all the AABB o the geometric instance.

    Returns boolean

    true if at least one geometric instance id inside pGeometricInstanceIds is valid and pAABBOut is therefore updated.

  • 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.

    Parameters

    Returns boolean

    true if setFixedResolution is in use, else false.

  • 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.

    Parameters

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

    Returns number

    The visual state of the given element, 0 is the element is invalid.

  • 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 string

    The id of the last picking request.

  • Gets the HD data loading progress of the engine.

    Tells the amount of data that has been already loaded before the HD loading procedure will stop. This returns a value in the range [0, 1], 1 meaning the HD loading procedure is over.

    This does not tell the amount of data that will be required to fully load the current point of view if resources were sufficient.

    Returns number

    The current HD data loading progress of the engine.

  • 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 LoadingStates

    The LoadingStates of the engine.

  • Gets the instances that have been transformed.

    Any instance that has been transformed with addMatrix or setMatrix will be included in pInstances.

    Parameters

    • pInstances: number[]
      out
      The list of transformed instances.

    Returns boolean

    trueif the call succeeded (i.e. pInstances is of the correct expected type).

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

    Returns HTMLElement

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

  • 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_files/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.getVisualAABB(lBitMask, lVisibleValueBit, lVisibleAABB);

    Please refer to the VisualStates for a list of possible values.

    Parameters

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

    Returns boolean

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

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

    Use this object at your own risks !!!.

    Returns WebGLRenderingContext

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

  • (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 InfiniteEngineInterfaceSignal.DisplayDone.

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

    Returns any

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

  • (WebXR) Gets the current XR Session (if any).

    If the session is not an XRSession, returns undefined.

    Returns any

    The current XRSession if called in an XR session, else undefined.

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

    Parameters

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

    Returns boolean

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

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

    Parameters

    • pId: string
      in
      The id of the callback to test.

    Returns boolean

    true if such a listener is installed for the given callback id.

  • Tells if anti aliasing is enabled.

    Returns boolean

    true if anti aliasing is enabled.

  • 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.

    Returns boolean

    true if the copyrighted watermark is enabled.

  • Tells if edge detection mechanism is enabled.

    Returns boolean

    true if edge detection is enabled.

  • 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 boolean

    true if the renderer is recycling the previous frame.

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

    Fires the event InfiniteEngineInterfaceSignal.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.

    If pPickOnlyClosest is true, then only the closest item under the picked point will be included, discarding other types of data if relevant.

    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).
    • pPickOnlyClosest: boolean
      in
      If set, only closest item(s) will be retrieved.

    Returns boolean

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

  • 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 InfiniteEngineInterfaceSignal.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.

    If pPickOnlyClosest is true, then only the closest item under the picked ray will be included, discarding other types of data if relevant.

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

    // the div to render to
    let lView3D: HTMLElement;

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

    // 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 += 1) {
    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, false);

    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.

    Parameters

    • pOrigin: Vector3
      in
      The origin of the ray.
    • pDirection: Vector3
      in
      The direction of the ray.
    • pPickOnlyClosest: boolean
      in
      If set, only closest items will be retrieved.

    Returns boolean

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

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

    (0,0) is on the upper left of screen. Fires the event InfiniteEngineInterfaceSignal.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.

    If pPickOnlyClosest is true, then only the closest items under the picked rectangle will be included, discarding other types of data if relevant.

    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).
    • pPickOnlyClosest: boolean
      in
      If set, only closest items will be retrieved.

    Returns boolean

    true if the rectangle is valid and not empty.

  • 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.

    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

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

  • 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.

    Parameters

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

      The listener function that gets removed.

    • pObject: Object

      The listener object that was used when addEventListener was called.

    Returns boolean

    true if the callback was removed else false.

  • 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.

    Parameters

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

      The listener function that gets removed.

    Returns boolean

    true if the callback was removed else false.

  • 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.

    Parameters

    • pId: string
      in
      The id returned by the call to addEventListener that you want to remove.

    Returns boolean

    true if the callback was removed else false.

  • Restores all geometric instances to their original positions.

    This discards any previous call to addMatrix, setMatrix.

    Returns void

  • Restores all the given geometric instances to their original positions.

    The transform will be restored for the given geometric instances.

    Returns true if at least one geometric instance id inside pGeometricInstanceIds is valid. Invalid geometric instance ids are silently discarded.

    Parameters

    • pGeometricInstanceIds: number | number[] | Uint32Array
      in
      The list of geometric instance ids to query.

    Returns boolean

    true if at least one geometric instance id inside pGeometricInstanceIds is valid.

  • 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 InfiniteEngineInterfaceSignal.ScreenshotReady signal will be fired shortly after.

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

    When using ScreenshotType.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_files/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.

    Parameters

    • pScreenshotType: ScreenshotType
      in
      The request screenshot type (image, geometric instance ids, etc).
    • pInBase64: boolean
      in
      If set to true, InfiniteImageInterface.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

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

  • Enables / disables anti aliasing.

    Anti aliasing is disabled by default.

    This is the same call as enableAntiAliasing.

    Parameters

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

    Returns boolean

    true is the call succeeded.

  • 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,A in the range [0,1]).

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

    Parameters

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

    Returns boolean

    true if the background has been successfully set.

  • 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.

    This is the same call as enableCopyrightedWatermark.

    Parameters

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

    Returns boolean

    true if the call succeeded.

  • Enables / disables edge detection mechanism.

    Edge detection is disabled by default.

    This is the same call as enableEdgeDetect.

    Parameters

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

    Returns boolean

    true if the call succeeded.

  • 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).

    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

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

  • Transforms the given geometric instances to the given matrix.

    The transform will be set for the given geometric instances, discarding any position previously set by addMatrix and the original matrices of the instances.

    Returns true if at least one geometric instance id inside pGeometricInstanceIds is valid and thus modified. Floating point numbers are considered invalid, and numbers outside the range of valid geometric instance ids are silently discarded (such numbers are not considered invalid, they are just discarded). Invalid geometric instance ids are also values that are not numbers. Invalid geometric instance ids are discarded, and if all values are discarded, the function returns false.

    Parameters

    • pGeometricInstanceIds: number | number[] | Uint32Array
      in
      the list of geometric instance ids to query.
    • pMatrix: Matrix4
      in
      the transformation to set to the current geometry position.

    Returns boolean

    true if at least one geometric instance id inside pGeometricInstanceIds is modified.

  • 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 boolean

    true if the call succeeded.

  • Enables / disables patch borders mechanism.

    Patch borders are disabled by default.

    patch borders rendering
    This is the same call as enablePatchBorders.

    Parameters

    • pEnable: boolean
      in
      If set, enables the patch borders rendering mechanism.

    Returns boolean

    true if the call succeeded.

  • Sets the rendering mode to use for shading.

    Returns true if pRenderingMode is a correct rendering mode. It also returns true if the rendering mode is unchanged by the call.

    available rendering modes
    Available rendering modes.

    Parameters

    Returns boolean

    true if call was successful.

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

    The view style will be altered with a position:relative.

    If InfiniteEngineViewType.options.useHardwareInstancing is not set (neither true nor false), then hardware instancing is set if getDefaultHardwareInstancingUsage is true. Hardware instancing is a hardware rendering optimization. Hardware instancing may cause trouble on some defect or very old graphic drivers.

    If InfiniteEngineViewType.options.useVertexArrayObjects is not set (neither true nor false), then Vertex Array Objects are used if getDefaultVertexArrayObjectsUsage is true. Vertex Array Objects are specific rendering objects that allows a significant reduction in function calls when rendering objects. They may cause trouble on some defect or very old graphic drivers.

    Parameters

    • pView: HTMLElement
      in
      The HTML element to render the DMU into.
    • Optional pForceEngineType: InfiniteEngineViewType
      in
      If set, the rendering can be forced to webgl1 or webxr (see InfiniteEngineViewType). When requesting a webxr session, pView must be set to undefined.

    Returns boolean

    true if the 3D view is set.

  • Gets a deep copy of the internal data of the InfiniteEngineInterface.

    Cut-planes and camera definitions are dumped.

    Please refer to JSON.stringify.

    Parameters

    • Optional pKey: any
      in
      Unused.

    Returns Object

    The internal InfiniteEngineInterface data.

  • 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_files/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 for a list of possible values.

    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) of the states that will be altered.
    • pBitValue: number
      in
      The bit value ("ORed" value of the VisualStates) of the states that will be set.

    Returns boolean

    trueif the call was issued.

  • 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_files/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 for a list of possible values.

    Parameters

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

    Returns boolean

    true if the call succeeded.