Skip to content
Snippets Groups Projects
Commit 899132a9 authored by Xiao Gui's avatar Xiao Gui
Browse files

exmpt MVP use siibra-api for template/parc/region


Co-authored-by: default avatarXiao Gui <xgui3783@gmail.com>
Co-authored-by: default avatarDaviti Gogshelidze <daviti1@mail.com>
parent 1f3c7a26
No related branches found
No related tags found
No related merge requests found
......@@ -2,8 +2,7 @@ import { InjectionToken } from "@angular/core";
import { Observable } from "rxjs";
import { IHasId } from "src/util/interfaces";
import { TBSDetail, TBSSummary } from "./receptor/type";
export const BS_ENDPOINT = new InjectionToken<string>('BS_ENDPOINT')
export { BS_ENDPOINT } from 'src/util/constants'
export type TRegion = {
name: string
......
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { BS_ENDPOINT } from "./constants";
import { BSFeatureReceptorModule } from "./receptor";
import { BsFeatureService } from "./service";
......@@ -10,10 +9,6 @@ import { BsFeatureService } from "./service";
BSFeatureReceptorModule,
],
providers: [
{
provide: BS_ENDPOINT,
useValue: BS_REST_URL || `https://brainscapes.apps-dev.hbp.eu`
},
BsFeatureService
],
exports: [
......
......@@ -30,7 +30,6 @@ export class SplashScreen implements AfterViewInit {
constructor(
private store: Store<IavRootStoreInterface>,
private constanceService: AtlasViewerConstantsServices,
private pureConstantService: PureContantService
) {
this.loadedTemplate$ = this.store.pipe(
......@@ -91,10 +90,6 @@ export class SplashScreen implements AfterViewInit {
})
)
}
get totalTemplates() {
return this.constanceService.templateUrls.length
}
}
@Pipe({
......
......@@ -26,12 +26,6 @@ export class AtlasViewerConstantsServices implements OnDestroy {
// instead of using window.location.href, which includes query param etc
public backendUrl = (BACKEND_URL && `${BACKEND_URL}/`.replace(/\/\/$/, '/')) || `${window.location.origin}${window.location.pathname}`
public totalTemplates = null
public getTemplateEndpoint$ = this.http.get(`${this.backendUrl}templates`, { responseType: 'json' }).pipe(
shareReplay(1)
)
public templateUrls = Array(100)
/* to be provided by KG in future */
......@@ -217,10 +211,7 @@ Raise/track issues at github repo: <a target = "_blank" href = "${this.repoUrl}"
this.dissmissUserLayerSnackbarMessage = this.dissmissUserLayerSnackbarMessageDesktop
}
}),
),
this.pureConstantService.getTemplateEndpoint$.subscribe(arr => {
this.totalTemplates = arr.length
})
)
}
private subscriptions: Subscription[] = []
......
......@@ -62,6 +62,7 @@ import { KgTosModule } from './ui/kgtos/module';
import { MouseoverModule } from './mouseoverModule/mouseover.module';
import { AtlasViewerRouterModule } from './routerModule';
import { MessagingGlue } from './messagingGlue';
import { BS_ENDPOINT } from './util/constants';
export function debug(reducer: ActionReducer<any>): ActionReducer<any> {
return function(state, action) {
......@@ -254,7 +255,11 @@ export function debug(reducer: ActionReducer<any>): ActionReducer<any> {
{
provide: WINDOW_MESSAGING_HANDLER_TOKEN,
useClass: MessagingGlue
}
},
{
provide: BS_ENDPOINT,
useValue: (BS_REST_URL || `https://brainscapes.apps-dev.hbp.eu`).replace(/\/$/, '')
},
],
bootstrap : [
AtlasViewer,
......
......@@ -115,3 +115,4 @@ export const compareLandmarksChanged: (prevLandmarks: any[], newLandmarks: any[]
}
export const CYCLE_PANEL_MESSAGE = `[spacebar] to cycle through views`
export const BS_ENDPOINT = new InjectionToken<string>('BS_ENDPOINT')
......@@ -83,3 +83,40 @@ export function switchMapWaitFor(opts: ISwitchMapWaitFor){
mapTo(arg)
)
}
export class MultiDimMap{
private map = new Map()
static GetKey(...arg: any[]){
let mapKey = ``
for (let i = 0; i < arg.length; i++) {
mapKey += arg[i]
}
return mapKey
}
set(...arg: any[]) {
const mapKey = MultiDimMap.GetKey(...(arg.slice(0, -1)))
this.map.set(mapKey, arg[arg.length - 1])
}
get(...arg: any[]) {
const mapKey = MultiDimMap.GetKey(...arg)
return this.map.get(mapKey)
}
delete(...arg: any[]) {
const mapKey = MultiDimMap.GetKey(...arg)
return this.map.delete(mapKey)
}
}
export function recursiveMutate<T>(arr: T[], getChildren: (obj: T) => T[], mutateFn: (obj: T) => void){
for (const obj of arr) {
mutateFn(obj)
recursiveMutate(
getChildren(obj),
getChildren,
mutateFn
)
}
}
import { Injectable, OnDestroy } from "@angular/core";
import { Inject, Injectable, OnDestroy } from "@angular/core";
import { Store, select } from "@ngrx/store";
import { Observable, merge, Subscription, of, forkJoin, fromEvent, combineLatest, timer } from "rxjs";
import { viewerConfigSelectorUseMobileUi } from "src/services/state/viewerConfig.store.helper";
import { shareReplay, tap, scan, catchError, filter, switchMap, map, take, distinctUntilChanged } from "rxjs/operators";
import { shareReplay, tap, scan, catchError, filter, switchMap, map, take, distinctUntilChanged, mapTo } from "rxjs/operators";
import { HttpClient } from "@angular/common/http";
import { viewerStateFetchedTemplatesSelector, viewerStateSetFetchedAtlases } from "src/services/state/viewerState.store.helper";
import { AtlasWorkerService } from "src/atlasViewer/atlasViewer.workerService.service";
import { LoggingService } from "src/logging";
import { viewerStateFetchedAtlasesSelector } from "src/services/state/viewerState/selectors";
import { BS_ENDPOINT } from "src/util/constants";
import { flattenReducer } from 'common/util'
import { TAtlas, TId, TParc, TRegion, TSpaceFull, TSpaceSummary } from "./siibraApiConstants/types";
import { MultiDimMap, recursiveMutate } from "./fn";
const getUniqueId = () => Math.round(Math.random() * 1e16).toString(16)
function parseId(id: TId){
if (typeof id === 'string') return id
return `${id.kg.kgSchema}/${id.kg.kgId}`
}
type THasId = {
['@id']: string
name: string
}
type TIAVAtlas = {
templateSpaces: ({ availableIn: THasId[] } & THasId)[]
parcellations: ({
availableIn: THasId[]
baseLayer: boolean
'@version': {
name: string
'@next': string
'@previous': string
'@this': string
}
} & THasId)[]
} & THasId
function getNehubaConfig(darkTheme: boolean) {
const backgrd = darkTheme
? [0,0,0,1]
: [1,1,1,1]
const rmPsp = darkTheme
? {"mode":"<","color":[0.1,0.1,0.1,1]}
:{"color":[1,1,1,1],"mode":"=="}
const drawSubstrates = darkTheme
? {"color":[0.5,0.5,1,0.2]}
: {"color":[0,0,0.5,0.15]}
const drawZoomLevels = darkTheme
? {"cutOff":150000}
: {"cutOff":200000,"color":[0.5,0,0,0.15] }
return {
"configName": "",
"globals": {
"hideNullImageValues": true,
"useNehubaLayout": {
"keepDefaultLayouts": false
},
"useNehubaMeshLayer": true,
"rightClickWithCtrlGlobal": false,
"zoomWithoutCtrlGlobal": false,
"useCustomSegmentColors": true
},
"zoomWithoutCtrl": true,
"hideNeuroglancerUI": true,
"rightClickWithCtrl": true,
"rotateAtViewCentre": true,
"enableMeshLoadingControl": true,
"zoomAtViewCentre": true,
"restrictUserNavigation": true,
"disableSegmentSelection": false,
"dataset": {
"imageBackground": backgrd,
"initialNgState": {
"showDefaultAnnotations": false,
"layers": {},
// "navigation": {
// "pose": {
// "position": {
// "voxelSize": [
// 21166.666015625,
// 20000,
// 21166.666015625
// ],
// "voxelCoordinates": [
// -21.8844051361084,
// 16.288618087768555,
// 28.418994903564453
// ]
// }
// },
// "zoomFactor": 350000
// },
"perspectiveOrientation": [
0.3140767216682434,
-0.7418519854545593,
0.4988985061645508,
-0.3195493221282959
],
"perspectiveZoom": 1922235.5293810747
}
},
"layout": {
"views": "hbp-neuro",
"planarSlicesBackground": backgrd,
"useNehubaPerspective": {
"enableShiftDrag": false,
"doNotRestrictUserNavigation": false,
"perspectiveSlicesBackground": backgrd,
"removePerspectiveSlicesBackground": rmPsp,
"perspectiveBackground": backgrd,
"fixedZoomPerspectiveSlices": {
"sliceViewportWidth": 300,
"sliceViewportHeight": 300,
"sliceZoom": 563818.3562426177,
"sliceViewportSizeMultiplier": 2
},
"mesh": {
"backFaceColor": backgrd,
"removeBasedOnNavigation": true,
"flipRemovedOctant": true
},
"centerToOrigin": true,
"drawSubstrates": drawSubstrates,
"drawZoomLevels": drawZoomLevels,
"hideImages": false,
"waitForMesh": true,
"restrictZoomLevel": {
"minZoom": 1200000,
"maxZoom": 3500000
}
}
}
}
}
@Injectable({
providedIn: 'root'
......@@ -17,96 +144,103 @@ const getUniqueId = () => Math.round(Math.random() * 1e16).toString(16)
export class PureContantService implements OnDestroy{
private subscriptions: Subscription[] = []
public useTouchUI$: Observable<boolean>
public fetchedAtlases$: Observable<any>
public darktheme$: Observable<boolean>
public totalAtlasesLength: number
public allFetchingReady$: Observable<boolean>
public backendUrl = (BACKEND_URL && `${BACKEND_URL}/`.replace(/\/\/$/, '/')) || `${window.location.origin}${window.location.pathname}`
private atlasParcSpcRegionMap = new MultiDimMap()
private _backendUrl = (BACKEND_URL && `${BACKEND_URL}/`.replace(/\/\/$/, '/')) || `${window.location.origin}${window.location.pathname}`
get backendUrl() {
console.warn(`something is using backendUrl`)
return this._backendUrl
}
/**
* TODO remove
* when removing, also remove relevant worker code
*/
private workerUpdateParcellation$ = fromEvent(this.workerService.worker, 'message').pipe(
filter((message: MessageEvent) => message && message.data && message.data.type === 'UPDATE_PARCELLATION_REGIONS'),
map(({ data }) => data)
)
private fetchTemplate = (templateUrl) => this.http.get(`${this.backendUrl}${templateUrl}`, { responseType: 'json' }).pipe(
switchMap((template: any) => {
if (template.nehubaConfig) {
return of(template)
}
if (template.nehubaConfigURL) {
return this.http.get(`${this.backendUrl}${template.nehubaConfigURL}`, { responseType: 'json' }).pipe(
map(nehubaConfig => {
return {
...template,
nehubaConfig,
}
}),
)
private getRegions(atlasId: string, parcId: string, spaceId: string){
return this.http.get<TRegion[]>(
`${this.bsEndpoint}/atlases/${encodeURIComponent(atlasId)}/parcellations/${encodeURIComponent(parcId)}/regions`,
{
params: {
space_id: spaceId
},
responseType: 'json'
}
return of(template)
}),
)
)
}
private processTemplate = template => forkJoin(
template.parcellations.map(parcellation => {
private getParcs(atlasId: string){
return this.http.get<TParc[]>(
`${this.bsEndpoint}/atlases/${encodeURIComponent(atlasId)}/parcellations`,
{ responseType: 'json' }
)
}
const id = getUniqueId()
private getParcDetail(atlasId: string, parcId: string) {
return this.http.get<TParc>(
`${this.bsEndpoint}/atlases/${encodeURIComponent(atlasId)}/parcellations/${encodeURIComponent(parcId)}`,
{ responseType: 'json' }
)
}
this.workerService.worker.postMessage({
type: 'PROPAGATE_PARC_REGION_ATTR',
parcellation,
inheritAttrsOpts: {
ngId: (parcellation as any ).ngId,
relatedAreas: [],
fullId: null
},
id
})
private getSpaces(atlasId: string){
return this.http.get<TSpaceSummary[]>(
`${this.bsEndpoint}/atlases/${encodeURIComponent(atlasId)}/spaces`,
{ responseType: 'json' }
)
}
return this.workerUpdateParcellation$.pipe(
filter(({ id: returnedId }) => id === returnedId),
take(1),
map(({ parcellation }) => parcellation)
)
})
)
private getSpaceDetail(atlasId: string, spaceId: string) {
return this.http.get<TSpaceFull>(
`${this.bsEndpoint}/atlases/${encodeURIComponent(atlasId)}/spaces/${encodeURIComponent(spaceId)}`,
{ responseType: 'json' }
)
}
public getTemplateEndpoint$ = this.http.get<any[]>(`${this.backendUrl}templates`, { responseType: 'json' }).pipe(
catchError(() => {
this.log.warn(`fetching root /tempaltes error`)
return of([])
}),
shareReplay(),
)
private getSpacesAndParc(atlasId: string) {
const spaces$ = this.getSpaces(atlasId).pipe(
switchMap(spaces => forkJoin(
spaces.map(space => this.getSpaceDetail(atlasId, parseId(space.id)))
))
)
const parcs$ = this.getParcs(atlasId).pipe(
// need not to get full parc data. first level gets all data
// switchMap(parcs => forkJoin(
// parcs.map(parc => this.getParcDetail(atlasId, parseId(parc.id)))
// ))
)
return forkJoin([
spaces$,
parcs$,
]).pipe(
map(([ templateSpaces, parcellations ]) => {
return { templateSpaces, parcellations }
})
)
}
public initFetchTemplate$ = this.getTemplateEndpoint$.pipe(
switchMap((templates: string[]) => merge(
...templates.map(templateName => this.fetchTemplate(templateName).pipe(
switchMap(template => this.processTemplate(template).pipe(
map(parcellations => {
return {
...template,
parcellations
}
})
))
)),
)),
catchError((err) => {
this.log.warn(`fetching templates error`, err)
return of(null)
}),
)
private getFullRegions(atlasId: string, parcId: string, spaceId: string) {
}
constructor(
private store: Store<any>,
private http: HttpClient,
private log: LoggingService,
private workerService: AtlasWorkerService,
@Inject(BS_ENDPOINT) private bsEndpoint: string,
){
this.darktheme$ = this.store.pipe(
select(state => state?.viewerState?.templateSelected?.useTheme === 'dark')
......@@ -117,21 +251,6 @@ export class PureContantService implements OnDestroy{
shareReplay(1)
)
this.fetchedAtlases$ = this.http.get(`${this.backendUrl.replace(/\/$/, '')}/atlases/`, { responseType: 'json' }).pipe(
catchError((err, obs) => of(null)),
filter(v => !!v),
tap((arr: any[]) => this.totalAtlasesLength = arr.length),
switchMap(atlases => merge(
...atlases.map(({ url }) => this.http.get(
/^http/.test(url)
? url
: `${this.backendUrl.replace(/\/$/, '')}/${url}`,
{ responseType: 'json' }))
)),
scan((acc, curr) => acc.concat(curr).sort((a, b) => (a.order || 1000) - (b.order || 1001)), []),
shareReplay(1)
)
this.subscriptions.push(
this.fetchedAtlases$.subscribe(fetchedAtlases =>
this.store.dispatch(
......@@ -141,7 +260,8 @@ export class PureContantService implements OnDestroy{
)
this.allFetchingReady$ = combineLatest([
this.getTemplateEndpoint$.pipe(
this.initFetchTemplate$.pipe(
filter(v => !!v),
map(arr => arr.length),
),
this.store.pipe(
......@@ -161,7 +281,247 @@ export class PureContantService implements OnDestroy{
)
}
private subscriptions: Subscription[] = []
private getAtlases$ = this.http.get<TAtlas[]>(
`${this.bsEndpoint}/atlases`,
{
responseType: 'json'
}
).pipe(
shareReplay(1)
)
public fetchedAtlases$: Observable<TIAVAtlas[]> = this.getAtlases$.pipe(
switchMap(atlases => {
return forkJoin(
atlases.map(
atlas => this.getSpacesAndParc(atlas.id).pipe(
map(({ templateSpaces, parcellations }) => {
return {
'@id': atlas.id,
name: atlas.name,
templateSpaces: templateSpaces.map(tmpl => {
return {
'@id': tmpl.id,
name: tmpl.name,
availableIn: tmpl.availableParcellations.map(parc => {
return {
'@id': parc.id,
name: parc.name
}
})
}
}),
parcellations: parcellations.map(parc => {
return {
'@id': parseId(parc.id),
name: parc.name,
baseLayer: parc.modality === 'cytoarchitecture',
'@version': {
'@next': parc.version?.next,
'@previous': parc.version?.prev,
'name': parc.version?.name,
'@this': parseId(parc.id)
},
availableIn: parc.availableSpaces.map(space => {
return {
'@id': space.id,
name: space.name,
/**
* TODO need original data format
*/
// originalDatasetFormats: [{
// name: "probability map"
// }]
}
})
}
})
}
})
)
)
)
}),
catchError((err, obs) => of([])),
tap((arr: any[]) => this.totalAtlasesLength = arr.length),
scan((acc, curr) => acc.concat(curr).sort((a, b) => (a.order || 1000) - (b.order || 1001)), []),
shareReplay(1)
)
public initFetchTemplate$ = this.fetchedAtlases$.pipe(
switchMap(atlases => {
return forkJoin(
atlases.map(atlas => this.getSpacesAndParc(atlas['@id']).pipe(
switchMap(({ templateSpaces, parcellations }) => {
const ngLayerObj = {}
return forkJoin(
templateSpaces.map(
tmpl => {
ngLayerObj[tmpl.id] = {}
return tmpl.availableParcellations.map(
parc => this.getRegions(atlas['@id'], parc.id, tmpl.id).pipe(
tap(regions => {
recursiveMutate(
regions,
region => region.children,
region => {
/**
* individual map(s)
* this should work for both fully mapped and interpolated
* in the case of interpolated, it sucks that the ngLayerObj will be set multiple times
*/
if (
tmpl.id in region.volumeSrc
&& 'collect' in region.volumeSrc[tmpl.id]
) {
const dedicatedMap = region.volumeSrc[tmpl.id]['collect'].filter(v => v.volume_type === 'neuroglancer/precomputed')
if (dedicatedMap.length === 1) {
const ngId = MultiDimMap.GetKey(atlas['@id'], tmpl.id, parc.id, dedicatedMap[0].id)
region['ngId'] = ngId
region['labelIndex'] = dedicatedMap[0].detail['neuroglancer/precomputed'].labelIndex
ngLayerObj[tmpl.id][ngId] = {
source: `precomputed://${dedicatedMap[0].url}`,
type: "segmentation",
transform: dedicatedMap[0].detail['neuroglancer/precomputed'].transform
}
}
}
/**
* if label index is defined
*/
if (!!region.labelIndex) {
const hemisphereKey = /left hemisphere/.test(region.name)
// these two keys are, unfortunately, more or less hardcoded
// which is less than ideal
? 'left hemisphere'
: /right hemisphere/.test(region.name)
? 'right hemisphere'
: 'whole brain'
/**
* TODO fix in siibra-api
*/
if (
tmpl.id !== 'minds/core/referencespace/v1.0.0/a1655b99-82f1-420f-a3c2-fe80fd4c8588'
&& parc.id === 'minds/core/parcellationatlas/v1.0.0/94c1125b-b87e-45e4-901c-00daee7f2579-25'
&& hemisphereKey === 'whole brain'
) {
region.labelIndex = null
return
}
const hemispheredNgId = MultiDimMap.GetKey(atlas['@id'], tmpl.id, parc.id, hemisphereKey)
region['ngId'] = hemispheredNgId
}
}
)
this.atlasParcSpcRegionMap.set(
atlas['@id'], tmpl.id, parc.id, regions
)
/**
* populate maps for parc
*/
for (const parc of parcellations) {
if (tmpl.id in (parc.volumeSrc || {})) {
// key: 'left hemisphere' | 'right hemisphere' | 'whole brain'
for (const key in parc.volumeSrc[tmpl.id]) {
for (const vol of parc.volumeSrc[tmpl.id][key]) {
if (vol.volume_type === 'neuroglancer/precomputed') {
const ngIdKey = MultiDimMap.GetKey(atlas['@id'], tmpl.id, parseId(parc.id), key)
ngLayerObj[tmpl.id][ngIdKey] = {
source: `precomputed://${vol.url}`,
type: "segmentation",
transform: vol.detail['neuroglancer/precomputed'].transform
}
}
}
}
}
}
})
)
)
}
).reduce(flattenReducer, [])
).pipe(
mapTo({ templateSpaces, parcellations, ngLayerObj })
)
}),
map(({ templateSpaces, ngLayerObj }) => {
return templateSpaces.map(tmpl => {
const darkTheme = tmpl.src_volume_type === 'mri'
const nehubaConfig = getNehubaConfig(darkTheme)
const initialLayers = nehubaConfig.dataset.initialNgState.layers
const tmplNgId = tmpl.name
const tmplAuxMesh = `${tmpl.name} auxmesh`
const precomputed = tmpl.volume_src.find(src => src.volume_type === 'neuroglancer/precomputed')
if (precomputed) {
initialLayers[tmplNgId] = {
type: "image",
source: `precomputed://${precomputed.url}`,
transform: precomputed.detail['neuroglancer/precomputed'].transform
}
}
const precompmesh = tmpl.volume_src.find(src => src.volume_type === 'neuroglancer/precompmesh')
const auxMeshes = []
if (precompmesh){
initialLayers[tmplAuxMesh] = {
source: `precompmesh://${precompmesh.url}`,
type: "segmentation",
transform: precompmesh.detail['neuroglancer/precompmesh'].transform
}
for (const auxMesh of precompmesh.detail['neuroglancer/precompmesh'].auxMeshes) {
auxMeshes.push({
...auxMesh,
ngId: tmplAuxMesh,
'@id': `${tmplAuxMesh} ${auxMesh.name}`,
visible: true
})
}
}
for (const key in (ngLayerObj[tmpl.id] || {})) {
initialLayers[key] = ngLayerObj[tmpl.id][key]
}
return {
name: tmpl.name,
'@id': tmpl.id,
fullId: tmpl.id,
useTheme: darkTheme ? 'dark' : 'light',
ngId: tmplNgId,
nehubaConfig,
auxMeshes,
parcellations: tmpl.availableParcellations.map(parc => {
const regions = this.atlasParcSpcRegionMap.get(atlas['@id'], tmpl.id, parc.id) || []
return {
fullId: parc.id,
'@id': parc.id,
name: parc.name,
regions
}
})
}
})
})
))
)
}),
map(arr => {
return arr.reduce(flattenReducer, [])
}),
catchError((err) => {
this.log.warn(`fetching templates error`, err)
return of(null)
}),
shareReplay(1),
)
ngOnDestroy(){
while(this.subscriptions.length > 0) this.subscriptions.pop().unsubscribe()
......
type THref = {
href: string
}
type TSpaceType = 'mri' | 'histology'
type TNgTransform = number[][]
type TVolumeType = 'nii' | 'neuroglancer/precomputed' | 'neuroglancer/precompmesh' | 'detailed maps'
type TParcModality = 'cytoarchitecture'
type TAuxMesh = {
name: string
labelIndicies: number[]
}
interface IVolumeTypeDetail {
'nii': null
'neuroglancer/precomputed': {
'neuroglancer/precomputed': {
'transform': TNgTransform
}
}
'neuroglancer/precompmesh': {
'neuroglancer/precompmesh': {
'auxMeshes': TAuxMesh[]
'transform': TNgTransform
}
}
'detailed maps': null
}
type TVolumeSrc<VolumeType extends keyof IVolumeTypeDetail> = {
id: string
name: string
url: string
volume_type: TVolumeType
detail: IVolumeTypeDetail[VolumeType]
}
type TKgIdentifier = {
kgSchema: string
kgId: string
}
type TVersion = {
name: string
prev: string | null
next: string | null
}
export type TId = string | { kg: TKgIdentifier }
export type TAtlas = {
id: string
name: string
links: {
parcellations: THref
spaces: THref
}
}
export type TSpaceSummary = {
id: {
kg: TKgIdentifier
},
name: string
links: {
self: THref
}
}
export type TParcSummary = {
id: string
name: string
}
export type TSpaceFull = {
id: string
name: string
key: string //???
type: string //???
url: string //???
ziptarget: string //???
src_volume_type: TSpaceType
volume_src: TVolumeSrc<keyof IVolumeTypeDetail>[]
availableParcellations: TParcSummary[]
links: {
templates: THref
parcellation_maps: THref
}
}
export type TParc = {
id: {
kg: TKgIdentifier
}
name: string
availableSpaces: {
id: string
name: string
}[]
links: {
self: THref
}
regions: THref
modality: TParcModality
version: TVersion
volumeSrc: {
[key: string]: {
[key: string]: TVolumeSrc<keyof IVolumeTypeDetail>[]
}
}
}
export type TRegion = {
name: string
children: TRegion[]
volumeSrc: {
[key: string]: {
[key: string]: TVolumeSrc<keyof IVolumeTypeDetail>[]
}
}
labelIndex?: number
rgb?: number[]
id?: {
kg: TKgIdentifier
}
/**
* missing
*/
originDatasets?: ({
filename: string
} & TKgIdentifier) []
position?: number[]
}
......@@ -10,7 +10,7 @@ import { IAuxMesh } from '../store'
export function getAuxMeshesAndReturnIColor(auxMeshes: IAuxMesh[]): IColorMap{
const returnVal: IColorMap = {}
for (const auxMesh of auxMeshes as IAuxMesh[]) {
const { ngId, labelIndicies, rgb } = auxMesh
const { ngId, labelIndicies, rgb = [255, 255, 255] } = auxMesh
const auxMeshColorMap = returnVal[ngId] || {}
for (const lblIdx of labelIndicies) {
auxMeshColorMap[lblIdx as number] = {
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment