import {BCFViewpointsPlugin} from '@xeokit/xeokit-sdk/src/plugins/BCFViewpointsPlugin/BCFViewpointsPlugin.js'
BCFViewpointsPlugin
Extends:
Viewer plugin that saves and loads BCF viewpoints as JSON objects.
BCF is a format for managing issues on a BIM project. This plugin's viewpoints conform to the BCF Version 2.1 specification.
Saving a BCF Viewpoint
In the example below we'll create a Viewer, load an .XKT
model into it using an XKTLoaderPlugin,
slice the model in half using a SectionPlanesPlugin, then use a BCFViewpointsPlugin#getViewpoint
to save a viewpoint to JSON, which we'll log to the JavaScript developer console.
import {Viewer, XKTLoaderPlugin, SectionPlanesPlugin, BCFViewpointsPlugin} from "xeokit-sdk.es.js";
// Create a Viewer
const viewer = new Viewer({
canvasId: "myCanvas",
transparent: true
});
// Add a XKTLoaderPlugin
const xktLoader = new XKTLoaderPlugin(viewer);
// Add a SectionPlanesPlugin
const sectionPlanes = new SectionPlanesPlugin(viewer);
// Add a BCFViewpointsPlugin
const bcfViewpoints = new BCFViewpointsPlugin(viewer);
// Load an .XKT model
const modelNode = xktLoader.load({
id: "myModel",
src: "./models/xkt/Schependomlaan.xkt",
edges: true // Emphasise edges
});
// Slice it in half
sectionPlanes.createSectionPlane({
id: "myClip",
pos: [0, 0, 0],
dir: [0.5, 0.0, 0.5]
});
// When model is loaded, set camera, select some objects and capture a BCF viewpoint to the console
modelNode.on("loaded", () => {
const scene = viewer.scene;
const camera = scene.camera;
camera.eye = [-2.37, 18.97, -26.12];
camera.look = [10.97, 5.82, -11.22];
camera.up = [0.36, 0.83, 0.40];
scene.setObjectsSelected([
"3b2U496P5Ebhz5FROhTwFH",
"2MGtJUm9nD$Re1_MDIv0g2",
"3IbuwYOm5EV9Q6cXmwVWqd",
"3lhisrBxL8xgLCRdxNG$2v",
"1uDn0xT8LBkP15zQc9MVDW"
], true);
const viewpoint = bcfViewpoints.getViewpoint();
const viewpointStr = JSON.stringify(viewpoint, null, 4);
console.log(viewpointStr);
});
Saving View Setup Hints
BCFViewpointsPlugin can optionally save hints in the viewpoint, which indicate how to set up the view when loading it again.
Here's the BCFViewpointsPlugin#getViewpoint call again, this time saving some hints:
const viewpoint = bcfViewpoints.getViewpoint({ // Options
spacesVisible: true, // Force IfcSpace types visible in the viewpoint (default is false)
spaceBoundariesVisible: false, // Show IfcSpace boundaries in the viewpoint (default is false)
openingsVisible: true // Force IfcOpening types visible in the viewpoint (default is false)
});
Loading a BCF Viewpoint
Assuming that we have our BCF viewpoint in a JSON object, let's now restore it with BCFViewpointsPlugin#setViewpoint:
bcfViewpoints.setViewpoint(viewpoint);
Handling BCF Incompatibility with xeokit's Camera
xeokit's Camera#look is the current 3D point-of-interest (POI).
A BCF viewpoint, however, has a direction vector instead of a POI, and so BCFViewpointsPlugin#getViewpoint saves xeokit's POI as a normalized vector from Camera#eye to Camera#look, which unfortunately loses that positional information. Loading the viewpoint with BCFViewpointsPlugin#setViewpoint will restore Camera#look to the viewpoint's camera position, offset by the normalized vector.
As shown below, providing a rayCast
option to setViewpoint
will set Camera#look to the closest
surface intersection on the direction vector. Internally, setViewpoint
supports this option by firing a ray
along the vector, and if that hits an Entity, sets Camera#look to ray's intersection point with the
Entity's surface.
bcfViewpoints.setViewpoint(viewpoint, {
rayCast: true // <<--------------- Attempt to set Camera#look to surface intersection point (default)
});
Dealing With Loaded Models That Are Not in the Viewpoint
If, for example, we load model "duplex", hide some objects, then save a BCF viewpoint with
BCFViewpointsPlugin#getViewpoint
, then load another model, "schependomlaan", then load the viewpoint again
with BCFViewpointsPlugin#setViewpoint
, then sometimes all of the objects in model "schependomlaan" become
visible, along with the visible objects in the viewpoint, which belong to model "duplex".
The reason is that, when saving a BCF viewpoint, BCF logic works like the following pseudo code:
If numVisibleObjects < numInvisibleObjects
save IDs of visible objects in BCF
exceptions = "visible objects"
else
save IDS of invisible objects in BCF
exceptions = "invisible objects"
When loading the viewpoint again:
If exceptions = "visible objects"
hide all objects
show visible objects in BCF
else
show all objects
hide invisible objects in BCF
When the exception is "visible objects", loading the viewpoint shows all the objects in the first, which includes objects in "schependomlaan", which can be confusing, because those were not even loaded when we first saved the viewpoint..
To solve this, we can supply a defaultInvisible
option to BCFViewpointsPlugin#getViewpoint, which
will force the plugin to save the IDs of all visible objects while making invisible objects the exception.
That way, when we load the viewpoint again, after loading model "schependomlaan", the plugin will hide all objects in the scene first (which will include objects belonging to model "schependomlaan"), then make the objects in the viewpoint visible (which will only be those of object "duplex").
const viewpoint = bcfViewpoints.getViewpoint({ // Options
//..
defaultInvisible: true
});
Behaviour with XKTLoaderPlugin globalizeObjectIds
Whenever we use XKTLoaderPlugin to load duplicate copies of the same model, after configuring
XKTLoaderPlugin#globalizeObjectIds true
to avoid Entity
ID clashes, this has consequences
for BCF viewpoints created by BCFViewpointsPlugin#getViewpoint.
When no duplicate copies of a model are loaded like this, viewpoints created by BCFViewpointsPlugin#getViewpoint will
continue to load as usual in other BIM viewers. Conversely, a viewpoint created for a single model in other BIM viewers
will continue to load as usual with BCFViewpointsPlugin
.
When duplicate copies of a model are loaded, however, viewpoints created by BCFViewpointsPlugin#getViewpoint
will contain certain changes that will affect the viewpoint's portability, however. Such viewpoints will
use authoring_tool_id
fields to save the globalized Entity#id
values, which enables the viewpoints to
capture the states of the individual Entitys
that represent the duplicate IFC elements. Take a look at the
following two examples to learn more.
- Example: Saving a BCF viewpoint containing duplicate models
- Example: Loading a BCF viewpoint containing duplicate models
Caveat: when loading a BCF viewpoint, we always assume that we have loaded in our target BIM viewer the same models that were
loaded in the viewpoint's original authoring application when the viewpoint was created. In the case of multi-model
viewpoints, the target BIM viewer, whether it be xeokit or another BIM viewer, will need to first have those exact
models loaded, with their objects having globalized IDs, following the same prefixing scheme we're using in
xeokit. Then, the viewpoint's authoring_tool_id
fields will be able to resolve to their objects within the
target viewer.
Constructor Summary
Public Constructor | ||
public |
constructor(viewer: Viewer, cfg: Object) |
Member Summary
Public Members | ||
public |
Identifies the authoring tool to include in BCF viewpoints saved by this plugin. |
|
public |
Identifies the originating system to include in BCF viewpoints saved by this plugin. |
Method Summary
Public Methods | ||
public |
destroy() Destroys this BCFViewpointsPlugin. |
|
public |
getViewpoint(options: *): * Saves viewer state to a BCF viewpoint. |
|
public |
setViewpoint(bcfViewpoint: *, options: *) Sets viewer state to the given BCF viewpoint. |
Inherited Summary
From class Plugin | ||
public |
ID for this Plugin, unique within its Viewer. |
|
public |
The Viewer that contains this Plugin. |
|
public |
destroy() Destroys this Plugin and removes it from its Viewer. |
|
public |
Logs an error message to the JavaScript developer console, prefixed with the ID of this Plugin. |
|
public |
Fires an event at this Plugin. |
|
public |
Logs a message to the JavaScript developer console, prefixed with the ID of this Plugin. |
|
public |
Subscribes to an event fired at this Plugin. |
|
public |
Logs a warning message to the JavaScript developer console, prefixed with the ID of this Plugin. |
Public Constructors
public constructor(viewer: Viewer, cfg: Object) source
Creates this Plugin and installs it into the given Viewer.
Override:
Plugin#constructorParams:
Name | Type | Attribute | Description |
viewer | Viewer | The Viewer. |
|
cfg | Object | Plugin configuration. |
|
cfg.id | String |
|
Optional ID for this plugin, so that we can find it within Viewer#plugins. |
cfg.originatingSystem | String |
|
Identifies the originating system for BCF records. |
cfg.authoringTool | String |
|
Identifies the authoring tool for BCF records. |
Public Members
Public Methods
public getViewpoint(options: *): * source
Saves viewer state to a BCF viewpoint.
Note that xeokit's Camera#look is the point-of-interest, whereas the BCF camera_direction
is a
direction vector. Therefore, we save camera_direction
as the vector from Camera#eye to Camera#look.
Params:
Name | Type | Attribute | Description |
options | * |
|
Options for getting the viewpoint. |
options.spacesVisible | Boolean |
|
Indicates whether |
options.openingsVisible | Boolean |
|
Indicates whether |
options.spaceBoundariesVisible | Boolean |
|
Indicates whether the boundaries of |
options.snapshot | Boolean |
|
Indicates whether the snapshot should be included in the viewpoint. |
options.defaultInvisible | Boolean |
|
When |
options.reverseClippingPlanes | Boolean |
|
When |
Return:
* | BCF JSON viewpoint object |
Example:
const viewer = new Viewer();
const bcfPlugin = new BCFPlugin(viewer, {
//...
});
const viewpoint = bcfPlugin.getViewpoint({ // Options - see constructor
spacesVisible: false, // Default
spaceBoundariesVisible: false, // Default
openingsVisible: false // Default
});
// viewpoint will resemble the following:
{
perspective_camera: {
camera_view_point: {
x: 0.0,
y: 0.0,
z: 0.0
},
camera_direction: {
x: 1.0,
y: 1.0,
z: 2.0
},
camera_up_vector: {
x: 0.0,
y: 0.0,
z: 1.0
},
field_of_view: 90.0
},
lines: [],
clipping_planes: [{
location: {
x: 0.5,
y: 0.5,
z: 0.5
},
direction: {
x: 1.0,
y: 0.0,
z: 0.0
}
}],
bitmaps: [],
snapshot: {
snapshot_type: png,
snapshot_data: "data:image/png;base64,......"
},
components: {
visibility: {
default_visibility: false,
exceptions: [{
ifc_guid: 4$cshxZO9AJBebsni$z9Yk,
originating_system: xeokit.io,
authoring_tool_id: xeokit/v1.0
}]
},
selection: [{
ifc_guid: "4$cshxZO9AJBebsni$z9Yk",
}]
}
}
public setViewpoint(bcfViewpoint: *, options: *) source
Sets viewer state to the given BCF viewpoint.
Note that xeokit's Camera#look is the point-of-interest, whereas the BCF camera_direction
is a
direction vector. Therefore, when loading a BCF viewpoint, we set Camera#look to the absolute position
obtained by offsetting the BCF camera_view_point
along camera_direction
.
When loading a viewpoint, we also have the option to find Camera#look as the closest point of intersection
(on the surface of any visible and pickable Entity) with a 3D ray fired from camera_view_point
in
the direction of camera_direction
.
Params:
Name | Type | Attribute | Description |
bcfViewpoint | * | BCF JSON viewpoint object, shows default visible entities and restores camera to initial default position. |
|
options | * |
|
Options for setting the viewpoint. |
options.rayCast | Boolean |
|
When |
options.immediate | Boolean |
|
When |
options.duration | Boolean |
|
Flight duration in seconds. Overrides CameraFlightAnimation#duration. Only applies when |
options.reset | Boolean |
|
When |
options.reverseClippingPlanes | Boolean |
|
When |
options.updateCompositeObjects | Boolean |
|
When |