Skip to content

Commit

Permalink
Overriding IfcElements render colors on loading file (#595)
Browse files Browse the repository at this point in the history
* basic elements coloring

* implementing view settings

* Linting and adjusting viewer mockup
  • Loading branch information
aozien committed Feb 17, 2023
1 parent 4dd85af commit 4ec449f
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 1 deletion.
6 changes: 6 additions & 0 deletions __mocks__/web-ifc-viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ const impl = {
material: null,
},
},
loader: {
ifcManager: {
parser: {},
},
},
},
clipper: {
active: false,
Expand Down Expand Up @@ -89,6 +94,7 @@ const impl = {
}),
setSelection: jest.fn(),
pickIfcItemsByID: jest.fn(),
loadIfcUrl: jest.fn(jest.fn(() => loadedModel)),
}
const constructorMock = ifcjsMock.IfcViewerAPI
constructorMock.mockImplementation(() => impl)
Expand Down
2 changes: 1 addition & 1 deletion src/Containers/CadView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ export default function CadView({
setIsLoading(true)

const ifcURL = (uploadedFile || filepath.indexOf('/') === 0) ? filepath : await getFinalURL(filepath, accessToken)
const loadedModel = await viewer.IFC.loadIfcUrl(
const loadedModel = await viewer.loadIfcUrl(
ifcURL,
!urlHasCameraParams(), // fitToFrame
(progressEvent) => {
Expand Down
14 changes: 14 additions & 0 deletions src/Infrastructure/IfcColor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* create an ifc color object
*
* @param {number} r the red component of the color as a fraction between 0 and 1
* @param {number} g the green component of the color as a fraction between 0 and 1
* @param {number} b the blue component of the color as a fraction between 0 and 1
* @param {number} o the opacity component of the color as a fraction between 0 and 1
*/
export default function IfcColor(r = 0, g = 0, b = 0, o = 1) {
this.x = r
this.y = g
this.z = b
this.w = o
}
18 changes: 18 additions & 0 deletions src/Infrastructure/IfcCustomViewSettings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import IfcColor from './IfcColor'


/**
* Object containig the coloring settings
*
* @param {IfcColor} defaultColor the color to be used if the id wasn't found in the provided map,
* if undefined the original element color will be used instead
* @param {object} idsToColorMap an object containing pairs of {[expressId]:[IfcColor]} to be used for those elements
*/
export default function IfcCustomViewSettings(defaultColor, idsToColorMap = {}) {
this.defaultColor = defaultColor
this.idsToColorMap = idsToColorMap

this.getElementColor = (expressId) => {
return this.idsToColorMap[expressId] ? this.idsToColorMap[expressId] : this.defaultColor
}
}
60 changes: 60 additions & 0 deletions src/Infrastructure/IfcElementsStyleManager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import IfcCustomViewSettings from './IfcCustomViewSettings'


/* eslint-disable jsdoc/no-undefined-types */
/**
* Overrides the default render functionality in the viewer
* and adds a postprocessing effect (outlining selected elements)
*/
export default class IfcElementsStyleManager {
/**
* constructs new class
*
* @param {IfcParser} the parser of the viewer
*/
constructor(parser) {
this.parser = parser
parser._overrideStyles = {}
parser.streamMesh = newStreamMeshFunction(parser)
}


/**
* Applys view settings to the next load call
*
* @param {IfcCustomViewSettings} settings an object containing expressId:IfcColor pairs
*/
setViewSettings(settings) {
this.parser._overrideStyles = settings ? settings : new IfcCustomViewSettings()
}
}


/* eslint-disable no-invalid-this */
/**
* Returns a new stream mesh function that uses
* the custom coloring provided
*
* @param {IfcParser} parser
* @return {Function} the new render function
*/
function newStreamMeshFunction(parser) {
/**
* Overrides the default stream function in the ifc parser
*
*/
function streamMesh(modelID, mesh) {
const placedGeometries = mesh.geometries
const size = placedGeometries.size()
for (let i = 0; i < size; i++) {
const placedGeometry = placedGeometries.get(i)
const itemMesh = this.getPlacedGeometry(modelID, mesh.expressID, placedGeometry)
const geom = itemMesh.geometry.applyMatrix4(itemMesh.matrix)
const overrideStyle = this._overrideStyles.getElementColor(mesh.expressID)
const color = overrideStyle !== undefined ? overrideStyle : placedGeometry.color
this.storeGeometryByMaterial(color, geom)
}
}

return streamMesh.bind(parser)
}
24 changes: 24 additions & 0 deletions src/Infrastructure/IfcViewerAPIExtended.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import {IfcViewerAPI} from 'web-ifc-viewer'
import IfcHighlighter from './IfcHighlighter'
import IfcViewsManager from './IfcElementsStyleManager'
import IfcCustomViewSettings from './IfcCustomViewSettings'


/* eslint-disable jsdoc/no-undefined-types */
/**
* Extending the original IFCViewerFunctionality
*/
Expand All @@ -12,6 +16,23 @@ export class IfcViewerAPIExtended extends IfcViewerAPI {
constructor(options) {
super(options)
this.highlighter = new IfcHighlighter(this.context)
this.viewsManager = new IfcViewsManager(this.IFC.loader.ifcManager.parser)
}


/**
* Loads the given IFC in the current scene.
*
* @param {string} url IFC as URL.
* @param {boolean} fitToFrame (optional) if true, brings the perspectiveCamera to the loaded IFC.
* @param {Function(event)} onProgress (optional) a callback function to report on downloading progress
* @param {Function} onError (optional) a callback function to report on loading errors
* @param {IfcCustomViewSettings} customViewSettings (optional) override the ifc elements file colors
* @return {IfcModel} ifcModel object
*/
async loadIfcUrl(url, fitToFrame, onProgress, onError, customViewSettings) {
this.viewsManager.setViewSettings(customViewSettings)
return await this.IFC.loadIfcUrl(url, fitToFrame, onProgress, onError)
}
/**
* Gets the expressId of the element that the mouse is pointing at
Expand All @@ -31,13 +52,16 @@ export class IfcViewerAPIExtended extends IfcViewerAPI {
const id = ifcManager.loader.ifcManager.getExpressId(mesh.geometry, found.faceIndex)
return {modelID: mesh.modelID, id}
}


/**
* gets a copy of the current selected expressIds in the scene
*
* @return {number[]} the selected express ids in the scene
*/
getSelectedIds = () => [...this._selectedExpressIds]


/**
* sets the current selected expressIds in the scene
*
Expand Down

0 comments on commit 4ec449f

Please sign in to comment.