Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Matrix api load model with custom colors #795

Merged
merged 5 commits into from
Sep 30, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 28 additions & 0 deletions cypress/e2e/integration/bldrs-inside-iframe.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -273,4 +273,32 @@ describe('bldrs inside iframe', () => {
assert.equal(msg.data['current'].length, 0)
})
})

it('should set defaultColor to gray, and color one element blue by view settings', () => {
cy.get('@iframe').trigger('keydown', {keyCode: KEYCODE_ESC})
cy.get('#lastMessageReceivedAction').contains(/ModelLoaded/i)
const defaultGrayColor = {
x: 0.85,
y: 0.85,
z: 0.85,
w: 1,
}
const colorBlue = {
x: 0.2,
y: 0.3,
z: 0.9,
w: 1,
}
cy.get('#txtSendMessageType').clear().type('ai.bldrs-share.ChangeViewSettings')
const msg = {
customViewSettings: {
defaultColor: defaultGrayColor,
globalIdsToColorMap: {
'3qoAS2W2r7m9vxQ0sGR5Rc': colorBlue,
},
},
}
cy.get('#txtSendMessagePayload').clear().type(JSON.stringify(msg), {parseSpecialCharSequences: false})
cy.get('#btnSendMessage').click()
})
})
8 changes: 5 additions & 3 deletions src/Containers/CadView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,9 @@ export default function CadView({
const [model, setModel] = useState(null)
const viewer = useStore((state) => state.viewer)
const setViewer = useStore((state) => state.setViewer)
const customViewSettings = useStore((state) => state.customViewSettings)
// setModelStore instead of setModel since there's already a state var with this name
const setModelStore = useStore((state) => state.setModel)
const setModelStore = useStore((state) => state.setModelStore)
const isNavPanelOpen = useStore((state) => state.isNavPanelOpen)
const isDrawerOpen = useStore((state) => state.isDrawerOpen)
const setCutPlaneDirections = useStore((state) => state.setCutPlaneDirections)
Expand Down Expand Up @@ -111,7 +112,7 @@ export default function CadView({
useEffect(() => {
debug().log('CadView#useEffect1[modelPath], calling onModelPath...')
onModelPath()
}, [modelPath])
}, [modelPath, customViewSettings])


// Viewer changes in onModelPath (above)
Expand Down Expand Up @@ -310,7 +311,8 @@ export default function CadView({
// TODO(pablo): error modal.
setIsLoading(false)
setAlertMessage(`Could not load file: ${filepath}`)
})
}, customViewSettings)

await viewer.isolator.setModel(loadedModel)

Privacy.recordEvent('select_content', {
Expand Down
34 changes: 30 additions & 4 deletions src/Infrastructure/IfcCustomViewSettings.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,39 @@ import IfcColor from './IfcColor'
*
* @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
* @param {object} expressIdsToColorMap an object containing pairs of {[expressId]:[IfcColor]} to be used for those elements
* @param {object} globalIdsToColorMap an object containing pairs of {[globalId]:[IfcColor]} to be used for those elements
*/
export default function IfcCustomViewSettings(defaultColor, idsToColorMap = {}) {
export default function IfcCustomViewSettings(defaultColor, expressIdsToColorMap = {}, globalIdsToColorMap = {}) {
this.defaultColor = defaultColor
this.idsToColorMap = idsToColorMap
this.expressIdsToColorMap = expressIdsToColorMap
this.globalIdsToColorMap = globalIdsToColorMap


this.getElementColor = (expressId) => {
return this.idsToColorMap[expressId] ? this.idsToColorMap[expressId] : this.defaultColor
return this.expressIdsToColorMap[expressId] ? this.expressIdsToColorMap[expressId] : this.defaultColor
}


/**
* Convert the color mapping for [globalId]:[color] to be [expressId]:[color] as well
*
* @param {object} api
* @param {number} modelID
* @param {IfcCustomViewSettings} customViewSettings
*/
this.normalizeGlobalIdSettings = (api, modelID) => {
const hasGlobalIdSettings = Object.keys(this.globalIdsToColorMap ?? []).length !== 0
if (hasGlobalIdSettings) {
const globalIds = Object.entries(this.globalIdsToColorMap)
// eslint-disable-next-line new-cap
api.CreateIfcGuidToExpressIdMapping(modelID)
const mappedToExpressIds = globalIds.map((pair) => [api.ifcGuidMap.get(modelID).get(pair[0]), pair[1]])
mappedToExpressIds.filter((pair) => pair[0]) // Remove global ids that weren't found
.forEach((pair) => {
this.expressIdsToColorMap[pair[0]] = pair[1] // Override the setting in the customViewSettingsObject
})
api.ifcGuidMap.delete(modelID)
}
}
}
2 changes: 2 additions & 0 deletions src/Infrastructure/IfcElementsStyleManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ function newInitializeLoadingStateFunction(parser) {
const viewSettings = await compileViewRules(this.state.api, modelID, this._rules)
this._overrideStyles = viewSettings
}
// Check if _overrideStyles has any setting using global id to be converted to expressId
this._overrideStyles?.normalizeGlobalIdSettings(this.state.api, modelID)
// eslint-disable-next-line new-cap
const shapes = await this.state.api.GetLineIDsWithType(modelID, IFCPRODUCTDEFINITIONSHAPE)
this.loadingState.total = shapes.size()
Expand Down
2 changes: 2 additions & 0 deletions src/WidgetApi/ApiEventsRegistry.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import ElementSelectionChangedEventDispatcher from './event-dispatchers/ElementS
import ModelLoadedEventDispatcher from './event-dispatchers/ModelLoadedEventDispatcher'
import HiddenElementsEventDispatcher from './event-dispatchers/HiddenElementsEventDispatcher'
import HighlightElementsEventHandler from './event-handlers/HighlightElementsEventHandler'
import ChangeViewSettingsEventHandler from './event-handlers/ChangeViewSettingsEventHandler'


/**
Expand Down Expand Up @@ -48,6 +49,7 @@ class ApiEventsRegistry {
new SuppressAboutDialogHandler(this.apiConnection),
new HideElementsEventHandler(this.apiConnection, this.searchIndex),
new UnhideElementsEventHandler(this.apiConnection, this.searchIndex),
new ChangeViewSettingsEventHandler(this.apiConnection),
]
for (const event of events) {
this.apiConnection.on(`action:${event.name}`, event.handler.bind(event))
Expand Down
43 changes: 43 additions & 0 deletions src/WidgetApi/event-handlers/ChangeViewSettingsEventHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import IfcCustomViewSettings from '../../Infrastructure/IfcCustomViewSettings'
import useStore from '../../store/useStore'
import ApiEventHandler from './ApiEventHandler'

/**
* Select Elements API event handler
*/
class ChangeViewSettingsEventHandler extends ApiEventHandler {
apiConnection = null
name = 'ai.bldrs-share.ChangeViewSettings'

/**
* constructor
*
* @param {object} apiConnection AbstractApiConnection
*/
constructor(apiConnection, navigation) {
super()
this.apiConnection = apiConnection
}

/**
* The handler for this event
*
* @param {object} data the event associated data
* @return {object} the response of the API call
*/
handler(data) {
if (!('customViewSettings' in data)) {
return this.apiConnection.missingArgumentResponse('customViewSettings')
}
const customViewSettings = data.customViewSettings
const customViewSettingsObject = new IfcCustomViewSettings(
customViewSettings.defaultColor,
customViewSettings.expressIdsToColorMap,
customViewSettings.globalIdsToColorMap,
)
useStore.setState({customViewSettings: customViewSettingsObject})
return this.apiConnection.successfulResponse({})
}
}

export default ChangeViewSettingsEventHandler
6 changes: 4 additions & 2 deletions src/store/IFCSlice.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@ export default function createIFCSlice(set, get) {
preselectedElementIds: null,
cameraControls: null,
loadedFileInfo: null,
setViewer: (viewer) => set(() => ({viewer: viewer})),
setModel: (model) => set(() => ({model: model})),
customViewSettings: null,
setViewerStore: (viewer) => set(() => ({viewerStore: viewer})),
setModelStore: (model) => set(() => ({model: model})),
setModelPath: (modelPath) => set(() => ({modelPath: modelPath})),
setSelectedElement: (element) => set(() => ({selectedElement: element})),
setSelectedElements: (elements) => set(() => ({selectedElements: elements})),
setElementTypesMap: (map) => set(() => ({elementTypesMap: map})),
setPreselectedElementIds: (elementIds) => set(() => ({preselectedElementIds: elementIds})),
setCameraControls: (cameraControls) => set(() => ({cameraControls: cameraControls})),
setLoadedFileInfo: (loadedFileInfo) => set(() => ({loadedFileInfo: loadedFileInfo})),
setCustomViewSettings: (customViewSettings) => set(() => ({customViewSettings: customViewSettings})),
}
}