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 exampleconst [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>