Преглед изворни кода

Merge branch 'master' of https://github.com/molstar/molstar

Alexander Rose пре 2 година
родитељ
комит
83c62c614b

+ 2 - 0
CHANGELOG.md

@@ -6,6 +6,8 @@ Note that since we don't clearly distinguish between a public and private interf
 
 ## [Unreleased]
 
+- Fixed a bug in mesh visualization (show backfaces when opacity < 1)
+
 ## [v3.28.0] - 2022-12-20
 
 - Show histogram in direct volume control point settings

+ 0 - 35
src/extensions/meshes/choice.ts

@@ -1,35 +0,0 @@
-/**
- * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Adam Midlik <midlik@gmail.com>
- */
-
-import { ParamDefinition as PD } from '../../mol-util/param-definition';
-
-
-/**
- * Represents a set of values to choose from, with a default value. Example:
- * ```
- * export const MyChoice = new Choice({ yes: 'I agree', no: 'Nope' }, 'yes');
- * export type MyChoiceType = Choice.Values<typeof MyChoice>; // 'yes'|'no'
- * ```
- */
-export class Choice<T extends string, D extends T> {
-    readonly defaultValue: D;
-    readonly options: [T, string][];
-    private readonly nameDict: { [value in T]: string };
-    constructor(opts: { [value in T]: string }, defaultValue: D) {
-        this.defaultValue = defaultValue;
-        this.options = Object.keys(opts).map(k => [k as T, opts[k as T]]);
-        this.nameDict = opts;
-    }
-    PDSelect(defaultValue?: T, info?: PD.Info): PD.Select<T> {
-        return PD.Select<T>(defaultValue ?? this.defaultValue, this.options, info);
-    }
-    prettyName(value: T): string {
-        return this.nameDict[value];
-    }
-}
-export namespace Choice {
-    export type Values<T extends Choice<any, any>> = T extends Choice<infer R, any> ? R : any;
-}

+ 23 - 61
src/extensions/meshes/examples.ts

@@ -6,31 +6,28 @@
 
 /** Testing examples for using mesh-extension.ts. */
 
-import { ParseMeshlistTransformer, MeshShapeTransformer, MeshlistData } from './mesh-extension';
-import * as MeshUtils from './mesh-utils';
-import { BACKGROUND_OPACITY, FOREROUND_OPACITY, InitMeshStreaming } from './mesh-streaming/transformers';
-import { MeshServerInfo } from './mesh-streaming/server-info';
-import { PluginUIContext } from '../../mol-plugin-ui/context';
-import { PluginContext } from '../../mol-plugin/context';
-import { StateObjectRef, StateObjectSelector } from '../../mol-state';
-import { Color } from '../../mol-util/color';
-import { Download } from '../../mol-plugin-state/transforms/data';
-import { StateTransforms } from '../../mol-plugin-state/transforms';
-import { Box3D } from '../../mol-math/geometry';
-import { ShapeRepresentation3D } from '../../mol-plugin-state/transforms/representation';
-import { ParamDefinition } from '../../mol-util/param-definition';
-import { PluginStateObject } from '../../mol-plugin-state/objects';
-import { createStructureRepresentationParams } from '../../mol-plugin-state/helpers/structure-representation-params';
+import { CIF } from '../../mol-io/reader/cif';
 import { Volume } from '../../mol-model/volume';
+import { createStructureRepresentationParams } from '../../mol-plugin-state/helpers/structure-representation-params';
 import { createVolumeRepresentationParams } from '../../mol-plugin-state/helpers/volume-representation-params';
+import { PluginStateObject } from '../../mol-plugin-state/objects';
+import { StateTransforms } from '../../mol-plugin-state/transforms';
+import { PluginContext } from '../../mol-plugin/context';
+import { StateObjectSelector } from '../../mol-state';
 import { Asset } from '../../mol-util/assets';
-import { CIF } from '../../mol-io/reader/cif';
+import { Color } from '../../mol-util/color';
+import { ParamDefinition } from '../../mol-util/param-definition';
+
+import { createMeshFromUrl } from './mesh-extension';
+import { MeshServerInfo } from './mesh-streaming/server-info';
+import { InitMeshStreaming } from './mesh-streaming/transformers';
+import * as MeshUtils from './mesh-utils';
 
 
 export const DB_URL = '/db'; // local
 
 
-export async function runMeshExtensionExamples(plugin: PluginUIContext, db_url: string = DB_URL) {
+export async function runMeshExtensionExamples(plugin: PluginContext, db_url: string = DB_URL) {
     console.time('TIME MESH EXAMPLES');
     // await runIsosurfaceExample(plugin, db_url);
     // await runMolsurfaceExample(plugin);
@@ -47,7 +44,7 @@ export async function runMeshExtensionExamples(plugin: PluginUIContext, db_url:
 }
 
 /** Example for downloading multiple separate segments, each containing 1 mesh. */
-export async function runMeshExample(plugin: PluginUIContext, segments: 'fg' | 'all', db_url: string = DB_URL) {
+export async function runMeshExample(plugin: PluginContext, segments: 'fg' | 'all', db_url: string = DB_URL) {
     const detail = 2;
     const segmentIds = (segments === 'all') ?
         [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17] // segment-16 has no detail-2
@@ -59,7 +56,7 @@ export async function runMeshExample(plugin: PluginUIContext, segments: 'fg' | '
 }
 
 /** Example for downloading multiple separate segments, each containing 1 mesh. */
-export async function runMeshExample2(plugin: PluginUIContext, segments: 'one' | 'few' | 'fg' | 'all') {
+export async function runMeshExample2(plugin: PluginContext, segments: 'one' | 'few' | 'fg' | 'all') {
     const detail = 1;
     const segmentIds = (segments === 'one') ? [15]
         : (segments === 'few') ? [1, 4, 7, 10, 16]
@@ -72,48 +69,13 @@ export async function runMeshExample2(plugin: PluginUIContext, segments: 'one' |
 }
 
 /** Example for downloading a single segment containing multiple meshes. */
-export async function runMultimeshExample(plugin: PluginUIContext, segments: 'fg' | 'all', detailChoice: 'best' | 'worst', db_url: string = DB_URL) {
+export async function runMultimeshExample(plugin: PluginContext, segments: 'fg' | 'all', detailChoice: 'best' | 'worst', db_url: string = DB_URL) {
     const urlDetail = (detailChoice === 'best') ? '2' : 'worst';
     const numDetail = (detailChoice === 'best') ? 2 : 1000;
     await createMeshFromUrl(plugin, `${db_url}/empiar-10070-multimesh-rounded/segments-${segments}/detail-${urlDetail}`, 0, numDetail, false, undefined);
 }
 
-/** Download data and create state tree hierarchy down to visual representation. */
-export async function createMeshFromUrl(plugin: PluginContext, meshDataUrl: string, segmentId: number, detail: number,
-    collapseTree: boolean, color?: Color, parent?: StateObjectSelector | StateObjectRef, transparentIfBboxAbove?: number,
-    name?: string, ownerId?: string) {
-
-    const update = parent ? plugin.build().to(parent) : plugin.build().toRoot();
-    const rawDataNodeRef = update.apply(Download,
-        { url: meshDataUrl, isBinary: true, label: `Downloaded Data ${segmentId}` },
-        { state: { isCollapsed: collapseTree } }
-    ).ref;
-    const parsedDataNode = await update.to(rawDataNodeRef)
-        .apply(StateTransforms.Data.ParseCif)
-        .apply(ParseMeshlistTransformer,
-            { label: undefined, segmentId: segmentId, segmentName: name ?? `Segment ${segmentId}`, detail: detail, ownerId: ownerId },
-            {}
-        )
-        .commit();
-
-    let transparent = false;
-    if (transparentIfBboxAbove !== undefined && parsedDataNode.data) {
-        const bbox = MeshlistData.bbox(parsedDataNode.data) || Box3D.zero();
-        transparent = Box3D.volume(bbox) > transparentIfBboxAbove;
-    }
-
-    await plugin.build().to(parsedDataNode)
-        .apply(MeshShapeTransformer, { color: color },)
-        .apply(ShapeRepresentation3D,
-            { alpha: transparent ? BACKGROUND_OPACITY : FOREROUND_OPACITY },
-            { tags: ['mesh-segment-visual', `segment-${segmentId}`] }
-        )
-        .commit();
-
-    return rawDataNodeRef;
-}
-
-export async function runMeshStreamingExample(plugin: PluginUIContext, source: MeshServerInfo.MeshSource = 'empiar', entryId: string = 'empiar-10070', serverUrl?: string, parent?: StateObjectSelector) {
+export async function runMeshStreamingExample(plugin: PluginContext, source: MeshServerInfo.MeshSource = 'empiar', entryId: string = 'empiar-10070', serverUrl?: string, parent?: StateObjectSelector) {
     const params = ParamDefinition.getDefaultValues(MeshServerInfo.Params);
     if (serverUrl) params.serverUrl = serverUrl;
     params.source = source;
@@ -122,7 +84,7 @@ export async function runMeshStreamingExample(plugin: PluginUIContext, source: M
 }
 
 /** Example for downloading a protein structure and visualizing molecular surface. */
-export async function runMolsurfaceExample(plugin: PluginUIContext) {
+export async function runMolsurfaceExample(plugin: PluginContext) {
     const entryId = 'pdb-7etq';
 
     // Node "https://www.ebi.ac.uk/pdbe/entry-files/download/7etq.bcif" ("transformer": "ms-plugin.download") -> var data
@@ -151,7 +113,7 @@ export async function runMolsurfaceExample(plugin: PluginUIContext) {
 }
 
 /** Example for downloading an EMDB density data and visualizing isosurface. */
-export async function runIsosurfaceExample(plugin: PluginUIContext, db_url: string = DB_URL) {
+export async function runIsosurfaceExample(plugin: PluginContext, db_url: string = DB_URL) {
     const entryId = 'emd-1832';
     const isoLevel = 2.73;
 
@@ -203,7 +165,7 @@ export async function runIsosurfaceExample(plugin: PluginUIContext, db_url: stri
 }
 
 
-export async function runCifMeshExample(plugin: PluginUIContext, api: string = 'http://localhost:9000/v2',
+export async function runCifMeshExample(plugin: PluginContext, api: string = 'http://localhost:9000/v2',
     source: MeshServerInfo.MeshSource = 'empiar', entryId: string = 'empiar-10070',
     segmentId: number = 1, detail: number = 10,
 ) {
@@ -211,8 +173,8 @@ export async function runCifMeshExample(plugin: PluginUIContext, api: string = '
     getMeshFromBcif(plugin, url);
 }
 
-async function getMeshFromBcif(plugin: PluginUIContext, url: string) {
-    const urlAsset = Asset.getUrlAsset(plugin.managers.asset, url); // QUESTION how is urlAsset better than normal `fetch`
+async function getMeshFromBcif(plugin: PluginContext, url: string) {
+    const urlAsset = Asset.getUrlAsset(plugin.managers.asset, url);
     const asset = await plugin.runTask(plugin.managers.asset.resolve(urlAsset, 'binary'));
     const parsed = await plugin.runTask(CIF.parseBinary(asset.data));
     if (parsed.isError) {

+ 55 - 59
src/extensions/meshes/mesh-extension.ts

@@ -15,14 +15,20 @@ import { Vec3 } from '../../mol-math/linear-algebra';
 import { Shape } from '../../mol-model/shape';
 import { ShapeProvider } from '../../mol-model/shape/provider';
 import { PluginStateObject } from '../../mol-plugin-state/objects';
-import { StateTransformer } from '../../mol-state';
+import { StateTransforms } from '../../mol-plugin-state/transforms';
+import { Download } from '../../mol-plugin-state/transforms/data';
+import { ShapeRepresentation3D } from '../../mol-plugin-state/transforms/representation';
+import { PluginContext } from '../../mol-plugin/context';
+import { StateObjectRef, StateObjectSelector, StateTransformer } from '../../mol-state';
 import { Task } from '../../mol-task';
 import { Color } from '../../mol-util/color';
-import { Material } from '../../mol-util/material';
 import { ParamDefinition as PD } from '../../mol-util/param-definition';
 import * as MeshUtils from './mesh-utils';
 
 
+export const BACKGROUND_OPACITY = 0.2;
+export const FOREROUND_OPACITY = 1;
+
 export const VolsegTransform: StateTransformer.Builder.Root = StateTransformer.builderFactory('volseg');
 
 
@@ -106,19 +112,17 @@ export namespace MeshlistData {
 }
 
 
-
 // // // // // // // // // // // // // // // // // // // // // // // //
 // Raw Data -> Parsed data
 
 export class MeshlistStateObject extends PluginStateObject.Create<MeshlistData>({ name: 'Parsed Meshlist', typeClass: 'Object' }) { }
-// QUESTION: is typeClass just for color, or does do something?
 
 export const ParseMeshlistTransformer = VolsegTransform({
     name: 'meshlist-from-string',
     from: PluginStateObject.Format.Cif,
     to: MeshlistStateObject,
     params: {
-        label: PD.Text(MeshlistStateObject.type.name, { isHidden: true }), // QUESTION: Is this the right way to pass a value to apply() without exposing it in GUI?
+        label: PD.Text(MeshlistStateObject.type.name, { isHidden: true }),
         segmentId: PD.Numeric(1, {}, { isHidden: true }),
         segmentName: PD.Text('Segment'),
         detail: PD.Numeric(1, {}, { isHidden: true }),
@@ -148,47 +152,32 @@ namespace MeshShapeProvider {
         return {
             label: 'Mesh',
             data: meshlist,
-            params: meshParamDef, // TODO how to pass the real params correctly?
+            params: meshShapeProviderParams,
             geometryUtils: Mesh.Utils,
             getShape: (ctx, data: MeshlistData) => MeshlistData.getShape(data, theColor),
         };
     }
 }
 
-/** Params for MeshShapeTransformer */
-const meshShapeParamDef = {
-    color: PD.Value<Color | undefined>(undefined), // undefined means random color
-};
-
-const meshParamDef: Mesh.Params = {
-    // These are basically original MS.Mesh.Params:
-    // BaseGeometry.Params
-    alpha: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }, { label: 'Opacity', isEssential: true, description: 'How opaque/transparent the representation is rendered.' }),
+const meshShapeProviderParams: Mesh.Params = {
+    ...Mesh.Params,
     quality: PD.Select<VisualQuality>('custom', VisualQualityOptions, { isEssential: true, description: 'Visual/rendering quality of the representation.' }), // use 'custom' when wanting to apply doubleSided
-    material: Material.getParam(),
-    clip: Mesh.Params.clip, // PD.Group(MS.Clip.Params),
-    instanceGranularity: PD.Boolean(false, { description: 'Use instance granularity for marker, transparency, clipping, overpaint, substance data to save memory.' }),
-    // Mesh.Params
-    doubleSided: PD.Boolean(true, BaseGeometry.CustomQualityParamInfo), // default: false (set true, to show at least something in weird cases)
-    flipSided: PD.Boolean(false, BaseGeometry.ShadingCategory),
-    flatShaded: PD.Boolean(false, BaseGeometry.ShadingCategory), // default: false (set true to see the real mesh vertices and triangles)
-    ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
-    xrayShaded: PD.Boolean(false, BaseGeometry.ShadingCategory), // this is like better opacity (angle-dependent), nice
-    transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory),
-    bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
-    bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
-    // TODO when I change values here, it has effect, but not if I change them in GUI
+    doubleSided: PD.Boolean(true, BaseGeometry.CustomQualityParamInfo),
+    // set `flatShaded`: true to see the real mesh vertices and triangles
+    transparentBackfaces: PD.Select('on', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory), // 'on' means: show backfaces with correct opacity, even when opacity < 1 (requires doubleSided) ¯\_(ツ)_/¯
 };
 
+
 export const MeshShapeTransformer = VolsegTransform({
     name: 'shape-from-meshlist',
     display: { name: 'Shape from Meshlist', description: 'Create Shape from Meshlist data' },
     from: MeshlistStateObject,
     to: PluginStateObject.Shape.Provider,
-    params: meshShapeParamDef
+    params: {
+        color: PD.Value<Color | undefined>(undefined), // undefined means random color
+    },
 })({
     apply({ a, params }) {
-        // you can look for example at ShapeFromPly in mol-plugin-state/tansforms/model.ts as an example
         const shapeProvider = MeshShapeProvider.fromMeshlistData(a.data, params.color);
         return new PluginStateObject.Shape.Provider(shapeProvider, { label: PluginStateObject.Shape.Provider.type.name, description: a.description });
     }
@@ -196,32 +185,39 @@ export const MeshShapeTransformer = VolsegTransform({
 
 
 // // // // // // // // // // // // // // // // // // // // // // // //
-// Shape -> Repr
-
-// type MeshRepr = MS.PluginStateObject.Representation3DData<MS.ShapeRepresentation<MS.ShapeProvider<any,any,any>, MS.Mesh, MS.Mesh.Params>, any>;
-
-// export const CustomMeshReprTransformer = VolsegTransform({
-//     name: 'custom-repr',
-//     from: MS.PluginStateObject.Shape.Provider, // later we can change this
-//     to: MS.PluginStateObject.Shape.Representation3D,
-// })({
-//     apply({ a }, globalCtx) {
-//         const repr: MeshRepr = createRepr(a.data); // TODO implement createRepr
-//         // have a look at MS.StateTransforms.Representation.ShapeRepresentation3D if you want to try implementing yourself
-//         return new MS.PluginStateObject.Shape.Representation3D(repr)
-//     },
-// })
-
-// export async function createMeshRepr(plugin: MS.PluginContext, data: any) {
-//     await plugin.build()
-//         .toRoot()
-//         .apply(CreateMyShapeTransformer, { data })
-//         .apply(MS.StateTransforms.Representation.ShapeRepresentation3D) // this should work
-//         // or .apply(CustomMeshRepr)
-//         .commit();
-// }
-
-// export function createRepr(reprData: MS.ShapeProvider<any,any,any>): MeshRepr {
-//     throw new Error('NotImplemented');
-//     return {} as MeshRepr;
-// }
+
+
+/** Download data and create state tree hierarchy down to visual representation. */
+export async function createMeshFromUrl(plugin: PluginContext, meshDataUrl: string, segmentId: number, detail: number,
+    collapseTree: boolean, color?: Color, parent?: StateObjectSelector | StateObjectRef, transparentIfBboxAbove?: number,
+    name?: string, ownerId?: string) {
+
+    const update = parent ? plugin.build().to(parent) : plugin.build().toRoot();
+    const rawDataNodeRef = update.apply(Download,
+        { url: meshDataUrl, isBinary: true, label: `Downloaded Data ${segmentId}` },
+        { state: { isCollapsed: collapseTree } }
+    ).ref;
+    const parsedDataNode = await update.to(rawDataNodeRef)
+        .apply(StateTransforms.Data.ParseCif)
+        .apply(ParseMeshlistTransformer,
+            { label: undefined, segmentId: segmentId, segmentName: name ?? `Segment ${segmentId}`, detail: detail, ownerId: ownerId },
+            {}
+        )
+        .commit();
+
+    let transparent = false;
+    if (transparentIfBboxAbove !== undefined && parsedDataNode.data) {
+        const bbox = MeshlistData.bbox(parsedDataNode.data) || Box3D.zero();
+        transparent = Box3D.volume(bbox) > transparentIfBboxAbove;
+    }
+
+    await plugin.build().to(parsedDataNode)
+        .apply(MeshShapeTransformer, { color: color },)
+        .apply(ShapeRepresentation3D,
+            { alpha: transparent ? BACKGROUND_OPACITY : FOREROUND_OPACITY },
+            { tags: ['mesh-segment-visual', `segment-${segmentId}`] }
+        )
+        .commit();
+
+    return rawDataNodeRef;
+}

+ 10 - 13
src/extensions/meshes/mesh-streaming/behavior.ts

@@ -19,9 +19,10 @@ import { Color } from '../../../mol-util/color';
 import { ColorNames } from '../../../mol-util/color/names';
 import { ParamDefinition as PD } from '../../../mol-util/param-definition';
 
-import { Choice } from '../choice';
+import { Choice } from '../../volumes-and-segmentations/helpers';
+import { MetadataWrapper } from '../../volumes-and-segmentations/volseg-api/utils';
+
 import { MeshlistData } from '../mesh-extension';
-import { Metadata } from '../metadata';
 import { MeshServerInfo } from './server-info';
 
 
@@ -33,8 +34,6 @@ const MAX_DETAIL = 10;
 const DEFAULT_DETAIL = 7; // TODO decide a reasonable default
 /** Segments whose bounding box volume is above this value (relative to the overall bounding box) are considered as background segments */
 export const BACKGROUND_SEGMENT_VOLUME_THRESHOLD = 0.5;
-// const DEBUG_IGNORED_SEGMENTS = new Set([13, 15]); // TODO remove
-const DEBUG_IGNORED_SEGMENTS = new Set(); // TODO remove
 
 
 export class MeshStreaming extends PluginStateObject.CreateBehavior<MeshStreaming.Behavior>({ name: 'Mesh Streaming' }) { }
@@ -116,7 +115,7 @@ export namespace MeshStreaming {
         private id: string;
         private ref: string = '';
         public parentData: MeshServerInfo.Data;
-        private metadata?: Metadata;
+        private metadata?: MetadataWrapper;
         public visuals?: { [tag: string]: VisualInfo };
         public backgroundSegments: { [segmentId: number]: boolean } = {};
         private focusObservable = this.plugin.behaviors.interaction.click.pipe( // QUESTION is this OK way to get focused segment?
@@ -165,7 +164,8 @@ export namespace MeshStreaming {
 
             if (!this.metadata) {
                 const response = await fetch(this.getMetadataUrl());
-                this.metadata = await response.json();
+                const rawMetadata = await response.json();
+                this.metadata = new MetadataWrapper(rawMetadata);
             }
 
             if (!this.visuals) {
@@ -209,13 +209,10 @@ export namespace MeshStreaming {
         }
 
         private initVisualInfos() {
-            const namesAndColors = Metadata.namesAndColorsBySegment(this.metadata!);
-
             const visuals: { [tag: string]: VisualInfo } = {};
-            for (const segid of Metadata.meshSegments(this.metadata!)) {
-                if (DEBUG_IGNORED_SEGMENTS.has(segid)) continue;
-                const name = namesAndColors[segid]?.name ?? DEFAULT_SEGMENT_NAME;
-                const color = namesAndColors[segid]?.color ?? DEFAULT_SEGMENT_COLOR;
+            for (const segid of this.metadata!.meshSegmentIds) {
+                const name = this.metadata?.getSegment(segid)?.biological_annotation.name ?? DEFAULT_SEGMENT_NAME;
+                const color = this.metadata?.getSegmentColor(segid) ?? DEFAULT_SEGMENT_COLOR;
                 for (const detailType of VisualInfo.DetailTypes) {
                     const visual: VisualInfo = {
                         tag: VisualInfo.tagFor(segid, detailType),
@@ -254,7 +251,7 @@ export namespace MeshStreaming {
                 const visual = this.visuals[tag];
                 const preferredDetail = (visual.detailType === 'high') ? highDetail : lowDetail;
                 if (preferredDetail !== undefined) {
-                    visual.detail = Metadata.getSufficientDetail(this.metadata!, visual.segmentId, preferredDetail);
+                    visual.detail = this.metadata!.getSufficientMeshDetail(visual.segmentId, preferredDetail);
                 }
             }
         }

+ 1 - 1
src/extensions/meshes/mesh-streaming/server-info.ts

@@ -7,7 +7,7 @@
 import { PluginStateObject } from '../../../mol-plugin-state/objects';
 import { ParamDefinition as PD } from '../../../mol-util/param-definition';
 
-import { Choice } from '../choice';
+import { Choice } from '../../volumes-and-segmentations/helpers';
 
 
 export const DEFAULT_MESH_SERVER = 'http://localhost:9000/v2';

+ 1 - 5
src/extensions/meshes/mesh-streaming/transformers.ts

@@ -13,15 +13,11 @@ import { Task } from '../../../mol-task';
 import { shallowEqualObjects } from '../../../mol-util';
 import { ParamDefinition as PD } from '../../../mol-util/param-definition';
 
-import { VolsegTransform, MeshlistData } from '../mesh-extension';
+import { BACKGROUND_OPACITY, FOREROUND_OPACITY, MeshlistData, VolsegTransform } from '../mesh-extension';
 import { MeshStreaming, NO_SEGMENT } from './behavior';
 import { MeshServerInfo } from './server-info';
 
 
-export const BACKGROUND_OPACITY = 0.2;
-export const FOREROUND_OPACITY = 1;
-
-
 // // // // // // // // // // // // // // // // // // // // // // // //
 
 export const MeshServerTransformer = VolsegTransform({

+ 0 - 135
src/extensions/meshes/metadata.ts

@@ -1,135 +0,0 @@
-/**
- * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Adam Midlik <midlik@gmail.com>
- */
-
-
-import { Color } from '../../mol-util/color';
-
-
-// TODO unify with Metadata in Volseg
-
-export interface Metadata {
-    grid: {
-        general: {
-            details: string,
-        },
-        volumes: Volumes,
-        segmentation_lattices: SegmentationLattices,
-        segmentation_meshes: SegmentationMeshes,
-    },
-    annotation: Annotation,
-}
-
-export interface Volumes {
-    volume_downsamplings: number[],
-    voxel_size: { [downsampling: number]: Vector3 },
-    origin: Vector3,
-    grid_dimensions: Vector3,
-    sampled_grid_dimensions: { [downsampling: number]: Vector3 },
-    mean: { [downsampling: number]: number },
-    std: { [downsampling: number]: number },
-    min: { [downsampling: number]: number },
-    max: { [downsampling: number]: number },
-    volume_force_dtype: string,
-}
-
-export interface SegmentationLattices {
-    segmentation_lattice_ids: number[],
-    segmentation_downsamplings: { [lattice: number]: number[] },
-}
-
-export interface Annotation {
-    name: string,
-    details: string,
-    segment_list: Segment[],
-}
-
-export interface Segment {
-    id: number,
-    colour: number[],
-    biological_annotation: BiologicalAnnotation,
-}
-
-export interface BiologicalAnnotation {
-    name: string,
-    external_references: { id: number, resource: string, accession: string, label: string, description: string }[]
-}
-
-export interface SegmentationMeshes {
-    mesh_component_numbers: {
-        segment_ids?: {
-            [segId: number]: {
-                detail_lvls: {
-                    [detail: number]: {
-                        mesh_ids: {
-                            [meshId: number]: {
-                                num_triangles: number,
-                                num_vertices: number
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-    detail_lvl_to_fraction: {
-        [lvl: number]: number
-    }
-}
-
-type Vector3 = [number, number, number];
-
-
-
-export namespace Metadata {
-    export function meshSegments(metadata: Metadata): number[] {
-        const segmentIds = metadata.grid.segmentation_meshes.mesh_component_numbers.segment_ids;
-        if (segmentIds === undefined) return [];
-        return Object.keys(segmentIds).map(s => parseInt(s));
-    }
-    export function meshSegmentDetails(metadata: Metadata, segmentId: number): number[] {
-        const segmentIds = metadata.grid.segmentation_meshes.mesh_component_numbers.segment_ids;
-        if (segmentIds === undefined) return [];
-        const details = segmentIds[segmentId].detail_lvls;
-        return Object.keys(details).map(s => parseInt(s));
-    }
-    /** Get the worst available detail level that is not worse than preferredDetail.
-     * If preferredDetail is null, get the worst detail level overall.
-     * (worse = greater number) */
-    export function getSufficientDetail(metadata: Metadata, segmentId: number, preferredDetail: number | null) {
-        let availDetails = meshSegmentDetails(metadata, segmentId);
-        if (preferredDetail !== null) {
-            availDetails = availDetails.filter(det => det <= preferredDetail);
-        }
-        return Math.max(...availDetails);
-    }
-    export function annotationsBySegment(metadata: Metadata): { [id: number]: Segment } {
-        const result: { [id: number]: Segment } = {};
-        for (const segment of metadata.annotation.segment_list) {
-            if (segment.id in result) {
-                throw new Error(`Duplicate segment annotation for segment ${segment.id}`);
-            }
-            result[segment.id] = segment;
-        }
-        return result;
-    }
-    export function dropSegments(metadata: Metadata, segments: number[]): void {
-        if (metadata.grid.segmentation_meshes.mesh_component_numbers.segment_ids === undefined) return;
-        const dropSet = new Set(segments);
-        metadata.annotation.segment_list = metadata.annotation.segment_list.filter(seg => !dropSet.has(seg.id));
-        for (const seg of segments) {
-            delete metadata.grid.segmentation_meshes.mesh_component_numbers.segment_ids[seg];
-        }
-    }
-    export function namesAndColorsBySegment(metadata: Metadata) {
-        const result: { [id: number]: { name: string, color: Color } } = {};
-        for (const segment of metadata.annotation.segment_list) {
-            if (segment.id in result) throw new Error(`Duplicate segment annotation for segment ${segment.id}`);
-            result[segment.id] = { name: segment.biological_annotation.name, color: Color.fromNormalizedArray(segment.colour, 0) };
-        }
-        return result;
-
-    }
-}

+ 1 - 1
src/extensions/volumes-and-segmentations/entry-meshes.ts

@@ -12,8 +12,8 @@ import { PluginCommands } from '../../mol-plugin/commands';
 import { Color } from '../../mol-util/color';
 import { ColorNames } from '../../mol-util/color/names';
 
-import { createMeshFromUrl } from '../meshes/examples';
 import { BACKGROUND_SEGMENT_VOLUME_THRESHOLD } from '../meshes/mesh-streaming/behavior';
+import { createMeshFromUrl } from '../meshes/mesh-extension';
 
 import { Segment } from './volseg-api/data';
 import { VolsegEntryData } from './entry-root';

+ 7 - 1
src/extensions/volumes-and-segmentations/volseg-api/utils.ts

@@ -4,6 +4,7 @@
  * @author Adam Midlik <midlik@gmail.com>
  */
 
+import { Color } from '../../../mol-util/color';
 import { Metadata, Segment } from './data';
 
 
@@ -33,6 +34,11 @@ export class MetadataWrapper {
         return this.segmentMap[segmentId];
     }
 
+    getSegmentColor(segmentId: number): Color | undefined {
+        const colorArray = this.getSegment(segmentId)?.colour;
+        return colorArray ? Color.fromNormalizedArray(colorArray, 0) : undefined;
+    }
+
     /** Get the list of detail levels available for the given mesh segment. */
     getMeshDetailLevels(segmentId: number): number[] {
         const segmentIds = this.raw.grid.segmentation_meshes.mesh_component_numbers.segment_ids;
@@ -65,4 +71,4 @@ export class MetadataWrapper {
         return vx * vy * vz * gx * gy * gz;
     }
 
-}
+}