diff --git a/src/atlasViewer/atlasViewer.apiService.service.ts b/src/atlasViewer/atlasViewer.apiService.service.ts index fed71fcf1bb89b9093b3719aeb7a268094ec0a5a..5d2652a506fa056e1fd4bbc828a4bec891920b99 100644 --- a/src/atlasViewer/atlasViewer.apiService.service.ts +++ b/src/atlasViewer/atlasViewer.apiService.service.ts @@ -38,6 +38,7 @@ export interface ILoadMesh { type: 'VTK' id: string url: string + customFragmentColor?: string } export const LOAD_MESH_TOKEN = new InjectionToken<(loadMeshParam: ILoadMesh) => void>('LOAD_MESH_TOKEN') @@ -76,7 +77,7 @@ export class AtlasViewerAPIServices implements OnDestroy{ public getNextUserRegionSelectHandler: () => IGetUserSelectRegionPr = () => { if (this.getUserToSelectRegion.length > 0) { return this.getUserToSelectRegion[this.getUserToSelectRegion.length - 1] - } + } else return null } @@ -84,7 +85,7 @@ export class AtlasViewerAPIServices implements OnDestroy{ if (this.getUserToSelectRegion.length > 0) { this.getUserToSelectRegion.pop() this.getUserToSelectRegionUI$.next([...this.getUserToSelectRegion]) - } + } } private s: Subscription[] = [] @@ -92,7 +93,7 @@ export class AtlasViewerAPIServices implements OnDestroy{ private onMouseClick(ev: any, next){ const { rs, spec } = this.getNextUserRegionSelectHandler() || {} if (!!rs) { - + let moSegments this.store.pipe( select(uiStateMouseOverSegmentsSelector), @@ -175,7 +176,7 @@ export class AtlasViewerAPIServices implements OnDestroy{ this.dismissDialog() this.dismissDialog = null } - + if (arr.length === 0) return of(null) const last = arr[arr.length - 1] @@ -350,7 +351,7 @@ export class AtlasViewerAPIServices implements OnDestroy{ }) this.s.push( - this.loadMesh$.subscribe(({ url, id, type }) => { + this.loadMesh$.subscribe(({ url, id, type, customFragmentColor = null }) => { if (!this.interactiveViewer.viewerHandle) { this.snackbar.open('No atlas loaded! Loading mesh failed!', 'Dismiss') } @@ -358,7 +359,7 @@ export class AtlasViewerAPIServices implements OnDestroy{ [id]: { type: 'mesh', source: `vtk://${url}`, - shader: `void main(){${FRAGMENT_EMIT_RED};}` + shader: `void main(){${customFragmentColor || FRAGMENT_EMIT_RED};}` } }) }) diff --git a/src/messaging/module.ts b/src/messaging/module.ts index 6c4049330f2637c140e38d0d490916b65e4bace3..f3e496eea20bbd34cb270640d839c948f17ec6d7 100644 --- a/src/messaging/module.ts +++ b/src/messaging/module.ts @@ -136,11 +136,12 @@ export class MesssagingModule{ isLoadingSnack?.dismiss() const meshId = 'bobby' if (this.loadMesh) { - const { objectUrl } = resp.result || {} + const { objectUrl, customFragmentColor } = resp.result || {} this.loadMesh({ type: 'VTK', id: meshId, - url: objectUrl + url: objectUrl, + customFragmentColor }) } else { this.snackbar.open(`Error: loadMesh method not injected.`) @@ -170,4 +171,4 @@ export class MesssagingModule{ if (response) this.whiteListedOrigins.add(origin) return response } -} \ No newline at end of file +} diff --git a/src/util/worker.js b/src/util/worker.js index fcb83f3fb035c7408bce6ff9d9f63e70a798e988..e15e0313e12e97a28c56b1a12a05b1f047a399fc 100644 --- a/src/util/worker.js +++ b/src/util/worker.js @@ -294,15 +294,10 @@ const processParcRegionAttr = (payload) => { const parseLineDataToVtk = (data, scale= 1, plotyMultiple) => { const lineCoordinates = [] + const colors = [] for (let i = 1; i < data.x.length; i++) { - // ToDo use neuron colors - // if (i+1 === data.x.length) { - // colors.push(data.marker.color[lineDataIndex-1]) - // break; - // } - if (data.x[i] !== null && data.x[i-1] !== null) { lineCoordinates.push([[ data.x[i-1] * plotyMultiple, @@ -313,6 +308,8 @@ const parseLineDataToVtk = (data, scale= 1, plotyMultiple) => { data.y[i] * plotyMultiple, data.z[i] * plotyMultiple, ]]) + + colors.push(data.marker.color[i-1]) } } @@ -326,7 +323,9 @@ const parseLineDataToVtk = (data, scale= 1, plotyMultiple) => { return returnString })() - const vtk = `${vtkHeader}\n` + + const customFragmentColor = getFragmentColorString(colors) + + const vtkString = `${vtkHeader}\n` + `POINTS ${coordinateLength*8} float\n` + lineCoordinatesArrayToString + `POLYGONS ${coordinateLength*12} ${coordinateLength*48}\n` + @@ -334,17 +333,45 @@ const parseLineDataToVtk = (data, scale= 1, plotyMultiple) => { `POINT_DATA ${coordinateLength*8}\n` + 'SCALARS label unsigned_char 1\n' + 'LOOKUP_TABLE none\n' + - getColorIds(coordinateLength*8) + getColorIds(colors) + + return {vtkString, customFragmentColor} +} + +const getFragmentColorString = (colors) => { + + const hexToRgb = (hex) => { + const [r, g, b] = hex.match(/\w\w/g).map(x => parseInt(x, 16)) + return `emitRGB(vec3(${r/255}, ${g/255}, ${b/255}))` + } - return vtk + const colorsUnique = colors.filter((cf, i) => colors[i-1] !== cf) + .map((color, j) => { + return `if (label > ${j - 0.01} && label < ${j + 0.01}) { ${hexToRgb(color)}; }` + }) + + const fragmentColorString = `${colorsUnique.join(' else ')} else {emitRGB(vec3(1.0, 0.1, 0.12));}` + return fragmentColorString } -const getColorIds = (n) => { +const getColorIds = (colors) => { let returnString = '' - for (let i=0; i<n-1; i++){ - returnString += '0\n' + + let colorId = 0 + + for (let i=0; i < colors.length; i++){ + if (i > 0 && colors[i] !== colors[i-1]) { + colorId += 1 + } + for (let j=0; j < 8; j++){ + if (i === colors.length-1 && j === 7) { + returnString += colorId + } else { + returnString += colorId + '\n' + } + } } - returnString += '0' + return returnString } @@ -452,7 +479,7 @@ onmessage = (message) => { } } if (plotyVtkUrl) URL.revokeObjectURL(plotyVtkUrl) - const vtkString = parseLineDataToVtk(plotlyData.traces[0], 5e-3, plotyMultiple) + const { vtkString, customFragmentColor} = parseLineDataToVtk(plotlyData.traces[0], 5e-3, plotyMultiple) plotyVtkUrl = URL.createObjectURL( new Blob([ encoder.encode(vtkString) ], { type: 'application/octet-stream' }) @@ -460,7 +487,8 @@ onmessage = (message) => { postMessage({ id, result: { - objectUrl: plotyVtkUrl + objectUrl: plotyVtkUrl, + customFragmentColor } }) } catch (e) {