Skip to main content
Version: v5.0

Enabling model comparison

Overview

This page demonstrates how to enable side-by-side model comparison of two different models in the IafViewer. To achieve this, it uses two instances of IafViewerDBM wrapped in a CompareView component.

Note: The material on this page serves as examples of how model comparison can be implemented by an application. Components such as CompareView are not officially part of the IafViewer. Similarly, the modes listed are also just examples. The examples shown demonstrate particular routes to implementing model comparison but there are other ways to implement this feature.

Main requirements for model comparison

Model comparison requires the following:

  • CompareView component
  • Two IafViewerDBM instances
  • Several required key props
  • Use one of the two available patterns of IafViewer behaviour

CompareView component

This component is required as it does the following:

  • Provides layout (either parallel or overlay)
  • Manages two child components
  • Handles image orientation (horizontal or vertical)

IafViewerDBM instances

The ViewerDBM instances do the following:

  • Each loads a different model
  • Share common configuration via spread props
  • Has unique props: model,modelVersionId, title

Required key props

The following props are required:

  • serverUrl - Graphics service URL
  • model - Model object with _id and _name
  • modelVersionId - Specific version to load
  • view3d, view2d, gid - view configurations

Modes

These modes of IafViewer behaviour are available:

  • Independent viewers - Each camera is independent of the other
  • Synchronized cameras - Cameras have a shared state

For more information, refer to the section Independent and sychronized modes.

Core components

You need to set up a layout wrapped component which manages the visual arrangement of the two viewers.

Refer to the code samples below.

Props

{
mode: 'parallel' | 'overlay', // Display mode
orientation: 'horizontal' | 'vertical', // Layout direction
children: ReactNode[] // Two child components (viewers)
}

Display modes

Parallel Mode - Side-by-side views with 50/50 split


<CompareView mode="parallel" orientation="horizontal">
<ViewerA />
<ViewerB />
</CompareView>

<CompareView mode="overlay" orientation="horizontal">
<ViewerA /> {/* Bottom layer /}
<ViewerB /> {/ Top layer with clipping */}
</CompareView>

IafViewerDBM

You also require a database-managed 3D/2D viewer component which loads and displays BIM models. See example code below.

Key Props for comparison

{
model: { // Model object
_id: string, // Model ID
_name: string, // Display name
_namespaces: object // Namespaces config
},
modelVersionId: string, // Specific version to load
serverUri: string, // Graphics service URL
title: string, // Viewer title (unique identifier)

// View configuration
view3d: object, // 3D view settings
view2d: object, // 2D view settings
gis: object, // GIS settings
}

Basic implementation

For a basic implementation of model comparison, do the following:

  1. Format models.
  2. Configure shared props.
  3. Set up render comparison.

Refer to the sections below for more information:

Format models

Refer to the same code below.

const formattedModels = currentModels.map(item => ({
_id: item.model.model,
_name: item.bimpk.filename.replace(/\.[^/.]+$/, ''),
_versionId: item.model.modelVersionId,
_namespaces: item.model?._namespaces
}));

Configure shared props

Refer to the same code below.

const viewerProps = {
serverUri: 'https://your-server.com',

view3d: {
enable: true,
showToolbar: false
},

view2d: {
enable: false
},

gis: {
enable: true,
showToolbar: false
},

enablePersistence: true
};

Set up render comparison

<CompareView mode="parallel" orientation="horizontal">
{/* First Viewer */}
<div style={{ height: '100%', width: '100%' }}>
<IafViewerDBM
{...viewerProps}
model={formattedModels[0]}
modelVersionId={formattedModels[0]._versionId}
title="Model A"
/>
</div>

{/* Second Viewer */}
<div style={{ height: '100%', width: '100%' }}>
<IafViewerDBM
{...viewerProps}
model={formattedModels[1]}
modelVersionId={formattedModels[1]._versionId}
title="Model B"
/>
</div>
</CompareView>

Complete example

For a complete example, refer to the code below.

import React from 'react';
import IafViewerDBM from '@invicara/iaf-viewer';
import CompareView from './comparison/CompareView.jsx';
import { IafProj } from '@dtplatform/platform-api';

class ModelComparison extends React.Component {
constructor(props) {
super(props);
this.state = {
view3d: { enable: true, showToolbar: false },
view2d: { enable: false }
};
}

render() {
// Get models from project
const currentProject = IafProj.getCurrent();
const currentModels = currentProject?._userAttributes?.currentModels || [];

// Format for IafViewerDBM
const formattedModels = currentModels.map(item => ({
_id: item.model.model,
_name: item.bimpk.filename.replace(/\\.[^/.]+$/, ''),
_versionId: item.model.modelVersionId,
_namespaces: item.model?._namespaces
}));

// Shared configuration
const viewerProps = {
serverUri: this.props.serverUri,
view3d: this.state.view3d,
view2d: this.state.view2d,
gis: { enable: true, showToolbar: false },
enablePersistence: true
};

// Render comparison
if (formattedModels.length >= 2) {
return (
<div style={{ width: '100%', height: '100%' }}>
<CompareView mode="parallel" orientation="horizontal">
<div style={{ height: '100%', width: '100%' }}>
<IafViewerDBM
{...viewerProps}
model={formattedModels[0]}
modelVersionId={formattedModels[0]._versionId}
title="Model A"
/>
</div>
<div style={{ height: '100%', width: '100%' }}>
<IafViewerDBM
{...viewerProps}
model={formattedModels[1]}
modelVersionId={formattedModels[1]._versionId}
title="Model B"
/>
</div>
</CompareView>
</div>
);
}

// Single viewer fallback
return (
<div style={{ height: '100%', width: '100%' }}>
<IafViewerDBM {...viewerProps} model={formattedModels[0]} />
</div>
);
}
}
export default ModelComparison;

Useful concepts

Shared props versus unique props

Note the differences between using shared props and unique props. Shared props will apply to both viewers whereas unique props are specific to each viewer.

Shared props (applies to both viewers)

Shared props include:

  • serverURL - graphics service endpoint
  • view3d, view2d, gis - view configurations
  • enablePersistence - settings persistence
  • saveSettings - settings save callback

Unique props (specific to both viewer)

Unique props include:

  • model - different model object for each viewer
  • modelVersionId - specific version identifier
  • title - unique totle for each instance

Independent and synchonized modes

Note the different modes of behavior for the camera in the IafViewer:

  • Independent - This is the default behavior
  • Synchronized - This is available via a custom implementation

See the different features of each mode, below.

Independent

The independent mode offers the following features:

  • Each viewer maintains its own camera position
  • Users interact with each view separately
  • This mode is useful for comparing different aspects of a model

Synchronized

The synchronized mode offers the following features:

  • Can share camera state between viewers
  • Good for direct visual comparison with aligned viewpoints

Refer to the sample code for synchronized camera below.

// Synchronized camera example
const [sharedCamera, setSharedCamera] = useState(undefined);

view3d: {
enable: true,
camera: sharedCamera, // Same camera for both
onCameraUpdate: {
callback: (camera) => setSharedCamera(camera)
}

Modes comparison

It is useful to compare different usage examples of independent viewers and synchronized cameras.

Mode 1: Independent viewers

In this example, the viewer operates independently with separate camera positions.

<CompareView mode="parallel" orientation="horizontal">
<IafViewerDBM
model={modelA}
view3d={{ enable: true, showToolbar: false }}
/>
<IafViewerDBM
model={modelB}
view3d={{ enable: true, showToolbar: false }}
/>
</CompareView>

Mode 2: Synchonized camera

In this example, both viewers maintain the same camera position.

const [sharedCamera, setSharedCamera] = useState(undefined);

const viewConfig = {
view3d: {
enable: true,
camera: sharedCamera,
onCameraUpdate: {
delay: 300,
callback: (camera) => setSharedCamera(camera)
}
}
};

<CompareView mode="parallel" orientation="horizontal">
<IafViewerDBM model={modelA} view3d={viewConfig.view3d} />
<IafViewerDBM model={modelB} view3d={viewConfig.view3d} />
</CompareView>