Newer
Older
import { Component, ElementRef, EventEmitter, OnDestroy, OnInit, Output, Inject, Optional } from "@angular/core";
import { fromEvent, Subscription, ReplaySubject, BehaviorSubject, Observable, race, timer, Subject } from 'rxjs'
import { debounceTime, filter, map, scan, startWith, mapTo, switchMap, take, skip } from "rxjs/operators";
import { AtlasWorkerService } from "src/atlasViewer/atlasViewer.workerService.service";
import { StateInterface as ViewerConfiguration } from "src/services/state/viewerConfig.store";
import { LoggingService } from "src/logging";
import { getExportNehuba, getViewer, setNehubaViewer } from "src/util/fn";
import '!!file-loader?context=third_party&name=main.bundle.js!export-nehuba/dist/min/main.bundle.js'
import '!!file-loader?context=third_party&name=chunk_worker.bundle.js!export-nehuba/dist/min/chunk_worker.bundle.js'
import { NEHUBA_INSTANCE_INJTKN, scanSliceViewRenderFn } from "../util";
import { strToRgb, deserialiseParcRegionId } from 'common/util'
const NG_LANDMARK_LAYER_NAME = 'spatial landmark layer'
const NG_USER_LANDMARK_LAYER_NAME = 'user landmark layer'
/**
* optimized for nehubaConfig.layout.useNehubaPerspective.fixedZoomPerspectiveSlices
* sliceZoom
* sliceViewportWidth
* sliceViewportHeight
*/
const NG_LANDMARK_CONSTANT = 1e-8
export const IMPORT_NEHUBA_INJECT_TOKEN = `IMPORT_NEHUBA_INJECT_TOKEN`
}
labelIndicies: number[]
}
export interface INehubaLifecycleHook{
onInit?: () => void
}
const scanFn: (acc: LayerLabelIndex[], curr: LayerLabelIndex) => LayerLabelIndex[] = (acc: LayerLabelIndex[], curr: LayerLabelIndex) => {
const { layer } = curr
const { name } = layer
const foundIndex = acc.findIndex(({ layer }) => layer.name === name)
if (foundIndex < 0) { return acc.concat(curr) } else { return acc.map((item, idx) => idx === foundIndex
...item,
labelIndicies: [...new Set([...item.labelIndicies, ...curr.labelIndicies])],
}
/**
* no selector is needed, as currently, nehubaviewer is created dynamically
*/
@Component({
templateUrl : './nehubaViewer.template.html',
styleUrls : [
private sliceviewLoading$: Observable<boolean>
public overrideShowLayers: string[] = []
get showLayersName() {
return [
...this.overrideShowLayers,
...Array.from(this.multiNgIdsLabelIndexMap.keys())
]
}
public lifecycle: INehubaLifecycleHook
public viewerPosInVoxel$ = new BehaviorSubject(null)
public viewerPosInReal$ = new BehaviorSubject(null)
public mousePosInVoxel$ = new BehaviorSubject(null)
public mousePosInReal$ = new BehaviorSubject(null)
private subscriptions: Subscription[] = []
@Output() public nehubaReady: EventEmitter<null> = new EventEmitter()
@Output() public layersChanged: EventEmitter<null> = new EventEmitter()
@Output() public viewerPositionChange: EventEmitter<any> = new EventEmitter()
@Output() public mouseoverLandmarkEmitter: EventEmitter<number | null> = new EventEmitter()
@Output() public mouseoverUserlandmarkEmitter: EventEmitter<string> = new EventEmitter()
@Output() public regionSelectionEmitter: EventEmitter<{segment: number, layer: {name?: string, url?: string}}> = new EventEmitter()
@Output() public errorEmitter: EventEmitter<any> = new EventEmitter()
public auxilaryMeshIndices: number[] = []
/* only used to set initial navigation state */
public initNav: any
public initRegions: any[]
public initNiftiLayers: any[] = []
private _dim: [number, number, number]
return this._dim
? this._dim
: [1.5e9, 1.5e9, 1.5e9]
}
public _s1$: any = null
public _s2$: any = null
public _s3$: any = null
public _s4$: any = null
public _s5$: any = null
public _s6$: any = null
public _s7$: any = null
public _s8$: any = null
public _s9$: any = null
Xiao Gui
committed
Xiao Gui
committed
this._s1$,
this._s2$,
this._s3$,
this._s4$,
this._s5$,
this._s6$,
Xiao Gui
committed
]
private createNehubaPromiseRs: Function
private createNehubaPromise = new Promise(rs => {
this.createNehubaPromiseRs = rs
})
public nehubaLoaded: boolean = false
public landmarksLoaded: boolean = false
constructor(
public elementRef: ElementRef,
private workerService: AtlasWorkerService,
private log: LoggingService,
@Inject(IMPORT_NEHUBA_INJECT_TOKEN) getImportNehubaPr: () => Promise<any>,
@Optional() @Inject(NEHUBA_INSTANCE_INJTKN) private nehubaViewer$: Subject<NehubaViewerUnit>,
if (this.nehubaViewer$) {
this.nehubaViewer$.next(this)
}
const fixedZoomPerspectiveSlices = this.config && this.config.layout && this.config.layout.useNehubaPerspective && this.config.layout.useNehubaPerspective.fixedZoomPerspectiveSlices
if (fixedZoomPerspectiveSlices) {
const { sliceZoom, sliceViewportWidth, sliceViewportHeight } = fixedZoomPerspectiveSlices
const dim = Math.min(sliceZoom * sliceViewportWidth, sliceZoom * sliceViewportHeight)
this._dim = [dim, dim, dim]
}
this.patchNG()
this.loadNehuba()
this.layersChangedHandler = this.nehubaViewer.ngviewer.layerManager.layersChanged.add(() => this.layersChanged.emit(null))
this.nehubaViewer.ngviewer.registerDisposer(this.layersChangedHandler)
.then(() => {
// all mutation to this.nehubaViewer should await createNehubaPromise
this.createNehubaPromiseRs()
})
.catch(e => this.errorEmitter.emit(e))
this.ondestroySubscriptions.push(
fromEvent(this.workerService.worker, 'message').pipe(
if (!message) {
// this.log.error('worker response message is undefined', message)
return false
}
if (!message.data) {
// this.log.error('worker response message.data is undefined', message.data)
return false
}
/* worker responded with not assembled landmark, no need to act */
return false
}
/* file url needs to be defined */
return false
}
return true
}),
debounceTime(100),
filter(e => this.templateId === e.data.template),
).subscribe(url => {
this.removeSpatialSearch3DLandmarks()
const _ = {}
source : `vtk://${url}`,
}
this.loadLayer(_)
)
this.ondestroySubscriptions.push(
fromEvent(this.workerService.worker, 'message').pipe(
if (!message) {
// this.log.error('worker response message is undefined', message)
if (!message.data) {
// this.log.error('worker response message.data is undefined', message.data)
/* worker responded with not assembled landmark, no need to act */
return false
}
/**
* nb url may be undefined
* if undefined, user have removed all user landmarks, and all that needs to be done
* is remove the user landmark layer
return true
}),
debounceTime(100),
this.removeuserLandmarks()
/**
* url may be null if user removes all landmarks
*/
if (!url) {
/**
* remove transparency from meshes in current layer(s)
*/
_[NG_USER_LANDMARK_LAYER_NAME] = {
type: 'mesh',
source: `vtk://${url}`,
shader: this.userLandmarkShader,
/**
* adding transparency to meshes in current layer(s)
*/
private _baseUrlToParcellationIdMap: Map<string, string> = new Map()
private _baseUrls: string[] = []
public numMeshesToBeLoaded: number = 0
public applyPerformanceConfig({ gpuLimit }: Partial<ViewerConfiguration>) {
if (gpuLimit && this.nehubaViewer) {
const limit = this.nehubaViewer.ngviewer.state.children.get('gpuMemoryLimit')
if (limit && limit.restoreState) {
limit.restoreState(gpuLimit)
}
}
}
/* required to check if correct landmarks are loaded */
return this._templateId
}
this._templateId = id
}
/** compatible with multiple parcellation id selection */
private _ngIds: string[] = []
this.createNehubaPromise
.then(() => {
this._ngIds.forEach(id => {
const oldlayer = this.nehubaViewer.ngviewer.layerManager.getLayerByName(id)
if (oldlayer) {oldlayer.setVisible(false) } else { this.log.warn('could not find old layer', id) }
})
this._ngIds = val
this.loadNewParcellation()
this.showAllSeg()
public spatialLandmarkSelectionChanged(labels: number[]) {
const getCondition = (label: number) => `if(label > ${label - 0.1} && label < ${label + 0.1} ){${FRAGMENT_EMIT_RED}}`
const newShader = `void main(){ ${labels.map(getCondition).join('else ')}else {${FRAGMENT_EMIT_WHITE}} }`
if (!this.nehubaViewer) {
if (!PRODUCTION) { this.log.warn('setting special landmark selection changed failed ... nehubaViewer is not yet defined') }
return
}
const landmarkLayer = this.nehubaViewer.ngviewer.layerManager.getLayerByName(NG_LANDMARK_LAYER_NAME)
if (!landmarkLayer) {
if (!PRODUCTION) { this.log.warn('landmark layer could not be found ... will not update colour map') }
return
}
if (labels.length === 0) {
landmarkLayer.layer.displayState.fragmentMain.restoreState(FRAGMENT_MAIN_WHITE)
} else {
landmarkLayer.layer.displayState.fragmentMain.restoreState(newShader)
}
}
public multiNgIdsLabelIndexMap: Map<string, Map<number, any>> = new Map()
Xiao Gui
committed
public navPosReal: [number, number, number] = [0, 0, 0]
public navPosVoxel: [number, number, number] = [0, 0, 0]
Xiao Gui
committed
public mousePosReal: [number, number, number] = [0, 0, 0]
public mousePosVoxel: [number, number, number] = [0, 0, 0]
Xiao Gui
committed
private _multiNgIdColorMap: Map<string, Map<number, {red: number, green: number, blue: number}>>
get multiNgIdColorMap() {
return this._multiNgIdColorMap
}
set multiNgIdColorMap(val) {
this._multiNgIdColorMap = val
}
private loadMeshes$: ReplaySubject<{labelIndicies: number[], layer: { name: string }}> = new ReplaySubject()
this.loadMeshes$.next({
labelIndicies,
public mouseOverSegment: number | null
public getNgHash: () => string = () => this.exportNehuba
? this.exportNehuba.getNgHash()
public loadNehuba() {
this.nehubaViewer = this.exportNehuba.createNehubaViewer(this.config, (err) => {
/* print in debug mode */
this.log.error(err)
/**
* Hide all layers except the base layer (template)
* Then show the layers referenced in multiNgIdLabelIndexMap
*/
const managedLayers = this.nehubaViewer.ngviewer.layerManager.managedLayers
for (const layerName of this.showLayersName) {
const layer = this.nehubaViewer.ngviewer.layerManager.getLayerByName(layerName)
if (layer) { layer.setVisible(true) } else { this.log.log('layer unavailable', layerName) }
}
Xiao Gui
committed
/* creation of the layout is done on next frame, hence the settimeout */
setTimeout(() => {
this.nehubaReady.emit(null)
this.newViewerInit()
this.loadNewParcellation()
this.sliceviewLoading$ = fromEvent(this.elementRef.nativeElement, 'sliceRenderEvent').pipe(
scan(scanSliceViewRenderFn, [ null, null, null ]),
map(arrOfFlags => arrOfFlags.some(flag => flag)),
startWith(true),
)
this.subscriptions.push(
this.loadMeshes$.pipe(
switchMap(layerLabelIdx =>
/**
* sometimes (e.g. when all slice views are minimised), sliceviewlaoding will not emit
* so if sliceviewloading does not emit another value (except the initial true value)
* force start loading of mesh
*/
race(
this.sliceviewLoading$.pipe(
skip(1)
),
timer(500).pipe(
mapTo(false)
)
).pipe(
filter(flag => !flag),
take(1),
mapTo(layerLabelIdx),
)
),
).subscribe(layersLabelIndex => {
let totalMeshes = 0
const { layer, labelIndicies } = layerLayerIndex
totalMeshes += labelIndicies.length
this.nehubaViewer.setMeshesToLoad(labelIndicies, layer)
}
// TODO implement total mesh to be loaded and mesh loading UI
const { onInit } = this.lifecycle || {}
onInit && onInit.call(this)
if (this.nehubaViewer$) {
this.nehubaViewer$.next(null)
}
this.subscriptions.pop().unsubscribe()
}
Xiao Gui
committed
})
this.ondestroySubscriptions.forEach(s => s.unsubscribe())
this.onDestroyCb.pop()()
}
this.nehubaViewer && this.nehubaViewer.dispose()
private onDestroyCb: Array<() => void> = []
private patchNG() {
const { LayerManager, UrlHashBinding } = this.exportNehuba.getNgPatchableObj()
// this.log.log('seturl hash')
// this.log.log('setting url hash')
}
UrlHashBinding.prototype.updateFromUrlHash = () => {
/* TODO find a more permanent fix to disable double click */
LayerManager.prototype.invokeAction = (arg) => {
/**
* The emitted value does not affect the region selection
* the region selection is taken care of in nehubaContainer
*/
const map = this.multiNgIdsLabelIndexMap.get(this.mouseOverLayer.name)
const region = map && map.get(this.mouseOverSegment)
if (arg === 'select') {
this.regionSelectionEmitter.emit({ segment: region, layer: this.mouseOverLayer })
/* eslint-disable-next-line @typescript-eslint/no-empty-function */
this.onDestroyCb.push(() => LayerManager.prototype.invokeAction = (_arg) => { /** in default neuroglancer, this function is invoked when selection occurs */ })
/**
* if selector is an empty object, select all layers
*/
return layerObj instanceof Object && Object.keys(layerObj).every(key =>
/**
* the property described by the selector must exist and ...
*/
/**
* if the selector is regex, test layer property
*/
( layerObj[key] instanceof RegExp
? layerObj[key].test(l[key])
/**
* if selector is string, test for strict equality
*/
: typeof layerObj[key] === 'string'
? layerObj[key] === l[key]
/**
* otherwise do not filter
*/
private userLandmarkShader: string = FRAGMENT_MAIN_WHITE
public updateUserLandmarks(landmarks: any[]) {
if (!this.nehubaViewer) {
return
this.workerService.worker.postMessage({
type : 'GET_USERLANDMARKS_VTK',
scale: Math.min(...this.dim.map(v => v * NG_LANDMARK_CONSTANT)),
landmarks : landmarks.map(lm => lm.position.map(coord => coord * 1e6)),
})
const parseLmColor = lm => {
if (!lm) return null
const { color } = lm
if (!color) return null
if (!Array.isArray(color)) return null
if (color.length !== 3) return null
const parseNum = num => (num >= 0 && num <= 255 ? num / 255 : 1).toFixed(3)
return `emitRGB(vec3(${color.map(parseNum).join(',')}));`
}
const appendConditional = (frag, idx) => frag && `if (label > ${idx - 0.01} && label < ${idx + 0.01}) { ${frag} }`
if (landmarks.some(parseLmColor)) {
this.userLandmarkShader = `void main(){ ${landmarks.map(parseLmColor).map(appendConditional).filter(v => !!v).join('else ')} else {${FRAGMENT_EMIT_WHITE}} }`
} else {
this.userLandmarkShader = FRAGMENT_MAIN_WHITE
}
}
this.removeLayer({
})
}
this.removeLayer({
name : NG_USER_LANDMARK_LAYER_NAME,
})
}
// pos in mm
public addSpatialSearch3DLandmarks(geometries: any[], scale?: number, type?: 'icosahedron') {
this.workerService.worker.postMessage({
type : 'GET_LANDMARKS_VTK',
template : this.templateId,
scale: Math.min(...this.dim.map(v => v * NG_LANDMARK_CONSTANT)),
geometry === null
? null
// gemoetry : [number,number,number] | [ [number,number,number][], [number,number,number][] ]
: isNaN(geometry[0])
? [geometry[0].map(triplets => triplets.map(coord => coord * 1e6)), geometry[1]]
public setLayerVisibility(condition: {name: string|RegExp}, visible: boolean) {
if (!this.nehubaViewer) {
return false
const viewer = this.nehubaViewer.ngviewer
viewer.layerManager.managedLayers
.filter(l => this.filterLayers(l, condition))
.map(layer => layer.setVisible(visible))
return false
const removeLayer = (i) => (viewer.layerManager.removeManagedLayer(i), i.name)
return viewer.layerManager.managedLayers
const viewer = this.nehubaViewer.ngviewer
return Object.keys(layerObj)
/* if the layer exists, it will not be loaded */
!viewer.layerManager.getLayerByName(key))
Array.from(this.multiNgIdsLabelIndexMap.keys()).forEach(ngId => {
Array.from(this.multiNgIdsLabelIndexMap.get(ngId).keys()).forEach(idx => {
this.nehubaViewer.hideSegment(idx, {
})
})
this.nehubaViewer.showSegment(0, {
Xiao Gui
committed
this.hideAllSeg()
Array.from(this.multiNgIdsLabelIndexMap.keys()).forEach(ngId => {
Xiao Gui
committed
})
Xiao Gui
committed
this.hideAllSeg()
Xiao Gui
committed
/**
* TODO tobe deprecated
*/
if (typeof array[0] === 'number') {
const reduceFn: (acc: Map<string, number[]>, curr: string) => Map<string, number[]> = (acc, curr) => {
if (!exist) {
newMap.set(ngId, [Number(labelIndex)])
} else {
newMap.set(ngId, [...exist, Number(labelIndex)])
}
const newMap: Map<string, number[]> = array.reduce(reduceFn, new Map())
/**
* TODO
* ugh, ugly code. cleanify
*/
* sometimes, ngId still happends to be undefined
*/
newMap.forEach((segs, ngId) => {
this.nehubaViewer.hideSegment(0, {
})
segs.forEach(seg => {
this.nehubaViewer.showSegment(seg, {
private vec3(pos: [number, number, number]) {
return this.exportNehuba.vec3.fromValues(...pos)
this.log.warn('setNavigationState > this.nehubaViewer is not yet defined')
Xiao Gui
committed
const {
orientation,
perspectiveOrientation,
perspectiveZoom,
position,
positionReal,
Xiao Gui
committed
} = newViewerState
Xiao Gui
committed
this.nehubaViewer.ngviewer.perspectiveNavigationState.zoomFactor.restoreState(perspectiveZoom)
Xiao Gui
committed
this.nehubaViewer.ngviewer.navigationState.zoomFactor.restoreState(zoom)
Xiao Gui
committed
this.nehubaViewer.ngviewer.perspectiveNavigationState.pose.orientation.restoreState( perspectiveOrientation )
Xiao Gui
committed
this.nehubaViewer.ngviewer.navigationState.pose.orientation.restoreState( orientation )
this.nehubaViewer.setPosition( this.vec3(position) , positionReal ? true : false )
Xiao Gui
committed
}
this.nehubaViewer.ngviewer.navigationState.pose.rotateRelative(this.vec3([0, 1, 0]), -amount / 4.0 * Math.PI / 180.0)
}
this.nehubaViewer.ngviewer.navigationState.pose.rotateRelative(this.vec3([1, 0, 0]), amount / 4.0 * Math.PI / 180.0)
}
this.nehubaViewer.ngviewer.navigationState.pose.rotateRelative(this.vec3([0, 0, 1]), amount / 4.0 * Math.PI / 180.0)
}
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
public toggleOctantRemoval(flag?: boolean) {
const ctrl = this.nehubaViewer?.ngviewer?.showPerspectiveSliceViews
if (!ctrl) {
this.log.error(`toggleOctantRemoval failed. this.nehubaViewer.ngviewer?.showPerspectiveSliceViews returns falsy`)
return
}
const newVal = typeof flag === 'undefined'
? !ctrl.value
: flag
ctrl.restoreState(newVal)
if (this.landmarksLoaded) {
/**
* showPerspectSliceView -> ! meshTransparency
*/
this.setMeshTransparency(!newVal)
}
}
public setMeshTransparency(flag: boolean){
/**
* remove transparency from meshes in current layer(s)
*/
for (const layerKey of this.multiNgIdsLabelIndexMap.keys()) {
const layer = this.nehubaViewer.ngviewer.layerManager.getLayerByName(layerKey)
if (layer) {
layer.layer.displayState.objectAlpha.restoreState(flag ? 0.2 : 1.0)
}
}
}
* @param arrayIdx label indices of the shown segment(s)
* @param ngId segmentation layer name
*/
const set = new Set(arrayIdx)
const newColorMap = new Map(
Array.from(this.multiNgIdColorMap.get(ngId).entries())
this.nehubaViewer.batchAddAndUpdateSegmentColors(newColorMap, {
name: ngId,
/* isn't this layer specific? */
/* TODO this is layer specific. need a way to distinguish between different segmentation layers */
this._s2$ = this.nehubaViewer.mouseOver.segment
this.mouseOverSegment = segment
this.mouseOverLayer = { ...layer }
})
Xiao Gui
committed
if (this.initRegions && this.initRegions.length > 0) {
this.hideAllSeg()
this.showSegs(this.initRegions)
}
this.initNiftiLayers.forEach(layer => this.loadLayer(layer))
this.hideAllSeg()
}
this._s8$ = this.nehubaViewer.mouseOver.segment.subscribe(({segment: segmentId, layer }) => {
const map = this.multiNgIdsLabelIndexMap.get(name)
const region = map && map.get(segmentId)
this.mouseoverSegmentEmitter.emit({
layer,
segment: region,
Xiao Gui
committed
// nehubaViewer.navigationState.all emits every time a new layer is added or removed from the viewer
Xiao Gui
committed
this._s3$ = this.nehubaViewer.navigationState.all
.distinctUntilChanged((a, b) => {
const {
orientation: o1,
perspectiveOrientation: po1,
perspectiveZoom: pz1,
position: p1,
} = a
const {
orientation: o2,
perspectiveOrientation: po2,
perspectiveZoom: pz2,
position: p2,
} = b
return [0, 1, 2, 3].every(idx => o1[idx] === o2[idx]) &&
[0, 1, 2, 3].every(idx => po1[idx] === po2[idx]) &&
pz1 === pz2 &&
z1 === z2
})
.subscribe(({ orientation, perspectiveOrientation, perspectiveZoom, position, zoom }) => {
Xiao Gui
committed
this.viewerState = {
orientation,
perspectiveOrientation,
perspectiveZoom,
zoom,
position,
Xiao Gui
committed
}
orientation : Array.from(orientation),
perspectiveOrientation : Array.from(perspectiveOrientation),
perspectiveZoom,
zoom,
Xiao Gui
committed
})
// TODO bug: mouseoverlandmarkemitter does not emit empty for VTK layer when user mouse click
this.ondestroySubscriptions.push(
this.nehubaViewer.mouseOver.layer
.filter(obj => obj.layer.name === NG_LANDMARK_LAYER_NAME)
)
this.ondestroySubscriptions.push(
this.nehubaViewer.mouseOver.layer
.filter(obj => obj.layer.name === NG_USER_LANDMARK_LAYER_NAME)
.subscribe(obj => this.mouseoverUserlandmarkEmitter.emit(obj.value)),
Xiao Gui
committed
this._s4$ = this.nehubaViewer.navigationState.position.inRealSpace
.subscribe(v => {
this.navPosReal = Array.from(v) as [number, number, number]
this.viewerPosInReal$.next(Array.from(v))
})
Xiao Gui
committed
this._s5$ = this.nehubaViewer.navigationState.position.inVoxels
.subscribe(v => {
this.navPosVoxel = Array.from(v) as [number, number, number]
this.viewerPosInVoxel$.next(Array.from(v))
})
Xiao Gui
committed
this._s6$ = this.nehubaViewer.mousePosition.inRealSpace
.subscribe(v => {
this.mousePosReal = Array.from(v) as [number, number, number]
this.mousePosInReal$.next(Array.from(v))
})
Xiao Gui
committed
this._s7$ = this.nehubaViewer.mousePosition.inVoxels
.subscribe(v => {
this.mousePosVoxel = Array.from(v) as [number, number, number]
this.mousePosInVoxel$.next(Array.from(v))
})
this._baseUrls = []
this.ngIds.map(id => {
const newlayer = this.nehubaViewer.ngviewer.layerManager.getLayerByName(id)
if (newlayer) {newlayer.setVisible(true) } else { this.log.warn('could not find new layer', id) }
if (!regex || !regex[2]) {
this.log.error('could not parse baseUrl')
if (regex[1] !== 'precomputed') {
this.log.error('sourceUrl is not precomputed')
const baseUrl = regex[2]
this._baseUrls.push(baseUrl)
this._baseUrlToParcellationIdMap.set(baseUrl, id)
const indicies = [
...Array.from(this.multiNgIdsLabelIndexMap.get(id).keys()),
]
this.loadMeshes(indicies, { name: id })
const obj = Array.from(this.multiNgIdsLabelIndexMap.keys()).map(ngId => {
return [
new Map(Array.from(
[
...this.multiNgIdsLabelIndexMap.get(ngId).entries(),
...this.auxilaryMeshIndices.map(val => {
return [val, {}]
).map((val: [number, any]) => ([val[0], this.getRgb(val[0], { ngId, rgb: val[1].rgb})])) as any),
}) as Array<[string, Map<number, {red: number, green: number, blue: number}>]>
if (this._s1$) {this._s1$.unsubscribe() }
if (this._s9$) {this._s9$.unsubscribe() }
const arr = Array.from(this.multiNgIdsLabelIndexMap.keys()).map(ngId => {
return this.nehubaViewer.getShownSegmentsObservable({
}).subscribe(arrayIdx => this.updateColorMap(arrayIdx, ngId))