diff --git a/src/apps/canvas/component/viewport.tsx b/src/apps/canvas/component/viewport.tsx index 5a1f97077cd0a81e81dc957bd053df70b32ed1ee..9f048fd4cd49fe7d634ffc61741137228e3f31fe 100644 --- a/src/apps/canvas/component/viewport.tsx +++ b/src/apps/canvas/component/viewport.tsx @@ -12,6 +12,9 @@ import { labelFirst } from 'mol-theme/label'; import { ButtonsType } from 'mol-util/input/input-observer'; import { throttleTime } from 'rxjs/operators' import { CombinedCameraMode } from 'mol-canvas3d/camera/combined'; +import { ColorParamComponent } from 'mol-app/component/parameter/color'; +import { Color } from 'mol-util/color'; +import { ParamDefinition as PD } from 'mol-util/param-definition' interface ViewportProps { app: App @@ -22,8 +25,11 @@ interface ViewportState { pickingInfo: string taskInfo: string cameraMode: CombinedCameraMode + backgroundColor: Color } +const BackgroundColorParam = PD.Color('Background Color', '', Color(0x000000)) + export class Viewport extends React.Component<ViewportProps, ViewportState> { private container: HTMLDivElement | null = null; private canvas: HTMLCanvasElement | null = null; @@ -32,7 +38,8 @@ export class Viewport extends React.Component<ViewportProps, ViewportState> { noWebGl: false, pickingInfo: '', taskInfo: '', - cameraMode: 'perspective' + cameraMode: 'perspective', + backgroundColor: Color(0x000000) }; handleResize() { @@ -45,7 +52,10 @@ export class Viewport extends React.Component<ViewportProps, ViewportState> { } this.handleResize() - this.setState({ cameraMode: this.props.app.canvas3d.camera.mode }) + this.setState({ + cameraMode: this.props.app.canvas3d.props.cameraMode, + backgroundColor: this.props.app.canvas3d.props.backgroundColor + }) const canvas3d = this.props.app.canvas3d @@ -132,19 +142,30 @@ export class Viewport extends React.Component<ViewportProps, ViewportState> { background: 'rgba(0, 0, 0, 0.2)' }} > - <span>Camera mode </span> - <select - value={this.state.cameraMode} - style={{width: '150'}} - onChange={e => { - const cameraMode = e.target.value as CombinedCameraMode - this.props.app.canvas3d.camera.mode = cameraMode - this.setState({ cameraMode }) + <div> + <span>Camera Mode </span> + <select + value={this.state.cameraMode} + style={{width: '150'}} + onChange={e => { + const p = { cameraMode: e.target.value as CombinedCameraMode } + this.props.app.canvas3d.setProps(p) + this.setState(p) + }} + > + <option value='perspective'>Perspective</option> + <option value='orthographic'>Orthographic</option> + </select> + </div> + <ColorParamComponent + param={BackgroundColorParam} + value={this.state.backgroundColor} + onChange={value => { + const p = { backgroundColor: value } + this.props.app.canvas3d.setProps(p) + this.setState(p) }} - > - <option value='perspective'>Perspective</option> - <option value='orthographic'>Orthographic</option> - </select> + /> </div> { this.state.taskInfo ? <div diff --git a/src/mol-app/component/color-theme.tsx b/src/mol-app/component/color-theme.tsx index 43f8d1290a4f9c99d24c29280cdbba03c59e17c1..e546c25bd4eaafd8da71102d14d122bf5a5b6c16 100644 --- a/src/mol-app/component/color-theme.tsx +++ b/src/mol-app/component/color-theme.tsx @@ -24,7 +24,7 @@ export class ColorThemeComponent extends React.Component<ColorThemeComponentProp render() { const ct = this.props.colorTheme return <div> - <span>Color Theme </span> + <span>Color Theme Info </span> {ct.description ? <div><i>{ct.description}</i></div> : ''} { diff --git a/src/mol-app/component/parameter/color.tsx b/src/mol-app/component/parameter/color.tsx new file mode 100644 index 0000000000000000000000000000000000000000..496254a490195d70079e45fcadea4cc26beadc4f --- /dev/null +++ b/src/mol-app/component/parameter/color.tsx @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import * as React from 'react' +import { ParamDefinition as PD } from 'mol-util/param-definition'; +import { ColorNames } from 'mol-util/color/tables'; +import { Color } from 'mol-util/color'; + +export interface ColorParamComponentProps { + param: PD.Color + value: Color + onChange(v: Color): void +} + +export interface ColorParamComponentState { + value: Color +} + +export class ColorParamComponent extends React.Component<ColorParamComponentProps, ColorParamComponentState> { + state = { + value: this.props.value + } + + onChange(value: Color) { + this.setState({ value }) + this.props.onChange(value) + } + + render() { + return <div> + <span>{this.props.param.label} </span> + <select value={this.state.value} onChange={e => this.onChange(Color(parseInt(e.target.value))) }> + {Object.keys(ColorNames).map(name => { + return <option key={name} value={(ColorNames as { [k: string]: Color})[name]}>{name}</option> + })} + </select> + </div>; + } +} \ No newline at end of file diff --git a/src/mol-app/component/parameters.tsx b/src/mol-app/component/parameters.tsx index 5c1748b7c45443a59badff9a722417769a77de88..02e47939a7d0a7b064c8482d3ea8ab88917a6347 100644 --- a/src/mol-app/component/parameters.tsx +++ b/src/mol-app/component/parameters.tsx @@ -12,6 +12,7 @@ import { RangeParamComponent } from './parameter/range'; import { SelectParamComponent } from './parameter/select'; import { MultiSelectParamComponent } from './parameter/multi-select'; import { TextParamComponent } from './parameter/text'; +import { ColorParamComponent } from './parameter/color'; interface ParametersProps<P extends PD.Params> { params: P @@ -35,6 +36,8 @@ function getParamComponent<P extends PD.Any>(p: PD.Any, value: P['defaultValue'] return <MultiSelectParamComponent param={p} value={value} onChange={onChange} /> case 'text': return <TextParamComponent param={p} value={value} onChange={onChange} /> + case 'color': + return <ColorParamComponent param={p} value={value} onChange={onChange} /> } return '' } diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts index ee2a3c419d1fd59cc3d3a8a74233db8c335b687a..d9460c5ee7d1a34f8c4ae7bbcd4799d5da87def8 100644 --- a/src/mol-canvas3d/canvas3d.ts +++ b/src/mol-canvas3d/canvas3d.ts @@ -63,6 +63,7 @@ interface Canvas3D { readonly camera: CombinedCamera downloadScreenshot: () => void getImageData: (variant: RenderVariant) => ImageData + setProps: (props: Partial<Canvas3DProps>) => void /** Returns a copy of the current Canvas3D instance props */ readonly props: Canvas3DProps @@ -341,6 +342,15 @@ namespace Canvas3D { reprCount, identified, didDraw, + setProps: (props: Partial<Canvas3DProps>) => { + if (props.cameraMode !== undefined && props.cameraMode !== camera.mode) { + camera.mode = props.cameraMode + } + if (props.backgroundColor !== undefined && props.backgroundColor !== renderer.props.clearColor) { + renderer.setClearColor(props.backgroundColor) + } + requestDraw(true) + }, get props() { return { diff --git a/src/mol-geo/geometry/color-data.ts b/src/mol-geo/geometry/color-data.ts index 59c2a16686bd0a4a97ee1e3877f51995965482c4..d9d798acc569fbbace36806b517015e0690e11fd 100644 --- a/src/mol-geo/geometry/color-data.ts +++ b/src/mol-geo/geometry/color-data.ts @@ -56,8 +56,7 @@ export function getColorThemeProps(props: ColorProps): ColorThemeProps { return p } -export function createColors(ctx: RuntimeContext, locationIt: LocationIterator, props: ColorProps, colorData?: ColorData): Promise<ColorData> { - const colorTheme = ColorTheme(getColorThemeProps(props)) +export function createColors(ctx: RuntimeContext, locationIt: LocationIterator, colorTheme: ColorTheme, colorData?: ColorData): Promise<ColorData> { switch (getGranularity(locationIt, colorTheme.granularity)) { case 'uniform': return createUniformColor(ctx, locationIt, colorTheme.color, colorData) case 'group': return createGroupColor(ctx, locationIt, colorTheme.color, colorData) diff --git a/src/mol-geo/geometry/direct-volume/direct-volume.ts b/src/mol-geo/geometry/direct-volume/direct-volume.ts index 1022a453f005b7de5c4af3ae8014ec10db689f5a..1e6575fbf7ea4bab48105808a5e02b754bf1f0c9 100644 --- a/src/mol-geo/geometry/direct-volume/direct-volume.ts +++ b/src/mol-geo/geometry/direct-volume/direct-volume.ts @@ -17,7 +17,9 @@ import { LocationIterator } from 'mol-geo/util/location-iterator'; import { TransformData } from '../transform-data'; import { createColors } from '../color-data'; import { createMarkers } from '../marker-data'; -import { Geometry } from '../geometry'; +import { Geometry, Theme } from '../geometry'; +import { transformPositionArray } from 'mol-geo/util'; +import { calculateBoundingSphere } from 'mol-gl/renderable/util'; const VolumeBox = Box() const RenderModeOptions = [['isosurface', 'Isosurface'], ['volume', 'Volume']] as [string, string][] @@ -75,16 +77,22 @@ export namespace DirectVolume { export const DefaultProps = PD.getDefaultValues(Params) export type Props = typeof DefaultProps - export async function createValues(ctx: RuntimeContext, directVolume: DirectVolume, transform: TransformData, locationIt: LocationIterator, props: Props): Promise<DirectVolumeValues> { + export async function createValues(ctx: RuntimeContext, directVolume: DirectVolume, transform: TransformData, locationIt: LocationIterator, theme: Theme, props: Props): Promise<DirectVolumeValues> { const { gridTexture, gridTextureDim } = directVolume + const { bboxSize, bboxMin, bboxMax, gridDimension, transform: gridTransform } = directVolume const { instanceCount, groupCount } = locationIt - const color = await createColors(ctx, locationIt, props) + const color = await createColors(ctx, locationIt, theme.color) const marker = createMarkers(instanceCount * groupCount) const counts = { drawCount: VolumeBox.indices.length, groupCount, instanceCount } - const { bboxSize, bboxMin, bboxMax, gridDimension, transform: gridTransform } = directVolume + const vertices = new Float32Array(VolumeBox.vertices) + transformPositionArray(gridTransform.ref.value, vertices, 0, vertices.length / 3) + const boundingSphere = calculateBoundingSphere( + vertices, vertices.length / 3, + transform.aTransform.ref.value, transform.instanceCount.ref.value + ) const controlPoints = getControlPointsFromString(props.controlPoints) const transferTex = createTransferFunctionTexture(controlPoints) @@ -99,6 +107,7 @@ export namespace DirectVolume { aPosition: ValueCell.create(VolumeBox.vertices as Float32Array), elements: ValueCell.create(VolumeBox.indices as Uint32Array), + boundingSphere: ValueCell.create(boundingSphere), uIsoValue: ValueCell.create(props.isoValueAbsolute), uBboxMin: bboxMin, @@ -117,6 +126,16 @@ export namespace DirectVolume { } export function updateValues(values: DirectVolumeValues, props: Props) { + const vertices = new Float32Array(values.aPosition.ref.value) + transformPositionArray(values.uTransform.ref.value, vertices, 0, vertices.length / 3) + const boundingSphere = calculateBoundingSphere( + vertices, Math.floor(vertices.length / 3), + values.aTransform.ref.value, values.instanceCount.ref.value + ) + if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) { + ValueCell.update(values.boundingSphere, boundingSphere) + } + ValueCell.updateIfChanged(values.uIsoValue, props.isoValueAbsolute) ValueCell.updateIfChanged(values.uAlpha, props.alpha) ValueCell.updateIfChanged(values.dUseFog, props.useFog) diff --git a/src/mol-geo/geometry/geometry.ts b/src/mol-geo/geometry/geometry.ts index e9c453d1420f2723c91a822925127f3fa0b1a6ee..2bf275c6a9590a367dcbdf54fcb75e886fa87985 100644 --- a/src/mol-geo/geometry/geometry.ts +++ b/src/mol-geo/geometry/geometry.ts @@ -10,13 +10,14 @@ import { RenderableState } from 'mol-gl/renderable'; import { ValueCell } from 'mol-util'; import { BaseValues } from 'mol-gl/renderable/schema'; import { Color } from 'mol-util/color'; -import { ColorThemeOptions, ColorThemeName, ColorScaleOptions, ColorScaleName } from 'mol-theme/color'; +import { ColorThemeOptions, ColorThemeName, ColorScaleOptions, ColorScaleName, ColorTheme } from 'mol-theme/color'; import { LocationIterator } from '../util/location-iterator'; -import { ColorType } from './color-data'; -import { SizeType } from './size-data'; +import { ColorType, getColorThemeProps } from './color-data'; +import { SizeType, getSizeThemeProps } from './size-data'; import { Lines } from './lines/lines'; import { ParamDefinition as PD } from 'mol-util/param-definition' import { DirectVolume } from './direct-volume/direct-volume'; +import { SizeTheme, SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; // @@ -35,6 +36,18 @@ export type VisualQuality = keyof typeof VisualQualityInfo export const VisualQualityNames = Object.keys(VisualQualityInfo) export const VisualQualityOptions = VisualQualityNames.map(n => [n, n] as [VisualQuality, string]) +export interface Theme { + color: ColorTheme + size: SizeTheme +} + +export function createTheme(props: Geometry.Props) { + return { + color: ColorTheme(getColorThemeProps(props)), + size: SizeTheme(getSizeThemeProps(props)) + } +} + // export type GeometryKindType = { @@ -64,9 +77,14 @@ export namespace Geometry { depthMask: PD.Boolean('Depth Mask', '', true), useFog: PD.Boolean('Use Fog', '', false), quality: PD.Select<VisualQuality>('Quality', '', 'auto', VisualQualityOptions), - colorTheme: PD.Select<ColorThemeName>('Color Theme', '', 'uniform', ColorThemeOptions), + + colorTheme: PD.Select<ColorThemeName>('Color Name', '', 'uniform', ColorThemeOptions), colorList: PD.Select<ColorScaleName>('Color Scale', '', 'default', ColorScaleOptions), colorValue: PD.Color('Color Value', '', Color(0xCCCCCC)), + + sizeTheme: PD.Select<SizeThemeName>('Size Name', '', 'uniform', SizeThemeOptions), + sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1), + sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1), } export const DefaultProps = PD.getDefaultValues(Params) export type Props = typeof DefaultProps diff --git a/src/mol-geo/geometry/lines/lines.ts b/src/mol-geo/geometry/lines/lines.ts index 22624aae78e876cd7a4193ebf31443c9d954e8fa..54954156927bbeeed26faf7d6b57115a64ad1256 100644 --- a/src/mol-geo/geometry/lines/lines.ts +++ b/src/mol-geo/geometry/lines/lines.ts @@ -7,18 +7,19 @@ import { ValueCell } from 'mol-util' import { Mat4 } from 'mol-math/linear-algebra' import { transformPositionArray/* , transformDirectionArray, getNormalMatrix */ } from '../../util'; -import { Geometry } from '../geometry'; +import { Geometry, Theme } from '../geometry'; import { RuntimeContext } from 'mol-task'; import { createColors } from '../color-data'; import { createMarkers } from '../marker-data'; import { createSizes } from '../size-data'; import { TransformData } from '../transform-data'; import { LocationIterator } from '../../util/location-iterator'; -import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; import { LinesValues } from 'mol-gl/renderable/lines'; import { Mesh } from '../mesh/mesh'; import { LinesBuilder } from './lines-builder'; import { ParamDefinition as PD } from 'mol-util/param-definition'; +import { calculateBoundingSphere } from 'mol-gl/renderable/util'; +import { Sphere3D } from 'mol-math/geometry'; /** Wide line */ export interface Lines { @@ -94,27 +95,36 @@ export namespace Lines { export const Params = { ...Geometry.Params, lineSizeAttenuation: PD.Boolean('Line Size Attenuation', '', false), - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 1, 0, 10, 0.1), - sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1), } export const DefaultProps = PD.getDefaultValues(Params) export type Props = typeof DefaultProps - export async function createValues(ctx: RuntimeContext, lines: Lines, transform: TransformData, locationIt: LocationIterator, props: Props): Promise<LinesValues> { + export async function createValues(ctx: RuntimeContext, lines: Lines, transform: TransformData, locationIt: LocationIterator, theme: Theme, props: Props): Promise<LinesValues> { const { instanceCount, groupCount } = locationIt - const color = await createColors(ctx, locationIt, props) - const size = await createSizes(ctx, locationIt, props) + const color = await createColors(ctx, locationIt, theme.color) + const size = await createSizes(ctx, locationIt, theme.size) const marker = createMarkers(instanceCount * groupCount) const counts = { drawCount: lines.lineCount * 2 * 3, groupCount, instanceCount } + const boundingSphere = Sphere3D.addSphere( + calculateBoundingSphere( + lines.startBuffer.ref.value, lines.lineCount, + transform.aTransform.ref.value, transform.instanceCount.ref.value + ), + calculateBoundingSphere( + lines.startBuffer.ref.value, lines.lineCount, + transform.aTransform.ref.value, transform.instanceCount.ref.value + ) + ) + return { aMapping: lines.mappingBuffer, aGroup: lines.groupBuffer, aStart: lines.startBuffer, aEnd: lines.endBuffer, elements: lines.indexBuffer, + boundingSphere: ValueCell.create(boundingSphere), ...color, ...size, ...marker, @@ -128,6 +138,20 @@ export namespace Lines { } export function updateValues(values: LinesValues, props: Props) { + const boundingSphere = Sphere3D.addSphere( + calculateBoundingSphere( + values.aStart.ref.value, Math.floor(values.aStart.ref.value.length / 3), + values.aTransform.ref.value, values.instanceCount.ref.value + ), + calculateBoundingSphere( + values.aEnd.ref.value, Math.floor(values.aEnd.ref.value.length / 3), + values.aTransform.ref.value, values.instanceCount.ref.value + ), + ) + if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) { + ValueCell.update(values.boundingSphere, boundingSphere) + } + Geometry.updateValues(values, props) ValueCell.updateIfChanged(values.dLineSizeAttenuation, props.lineSizeAttenuation) } diff --git a/src/mol-geo/geometry/mesh/mesh.ts b/src/mol-geo/geometry/mesh/mesh.ts index e42c7f40190f49b72fb7ea52f5d8b3fd21070161..9d4ca0deba32cafc054e75dce3b86452c416eba7 100644 --- a/src/mol-geo/geometry/mesh/mesh.ts +++ b/src/mol-geo/geometry/mesh/mesh.ts @@ -10,13 +10,14 @@ import { Vec3, Mat4 } from 'mol-math/linear-algebra' import { Sphere3D } from 'mol-math/geometry' import { transformPositionArray/* , transformDirectionArray, getNormalMatrix */ } from '../../util'; import { MeshValues } from 'mol-gl/renderable'; -import { Geometry } from '../geometry'; +import { Geometry, Theme } from '../geometry'; import { createMarkers } from '../marker-data'; import { TransformData } from '../transform-data'; import { LocationIterator } from '../../util/location-iterator'; import { createColors } from '../color-data'; import { ChunkedArray } from 'mol-data/util'; import { ParamDefinition as PD } from 'mol-util/param-definition'; +import { calculateBoundingSphere } from 'mol-gl/renderable/util'; export interface Mesh { readonly kind: 'mesh', @@ -346,18 +347,24 @@ export namespace Mesh { export const DefaultProps = PD.getDefaultValues(Params) export type Props = typeof DefaultProps - export async function createValues(ctx: RuntimeContext, mesh: Mesh, transform: TransformData, locationIt: LocationIterator, props: Props): Promise<MeshValues> { + export async function createValues(ctx: RuntimeContext, mesh: Mesh, transform: TransformData, locationIt: LocationIterator, theme: Theme, props: Props): Promise<MeshValues> { const { instanceCount, groupCount } = locationIt - const color = await createColors(ctx, locationIt, props) + const color = await createColors(ctx, locationIt, theme.color) const marker = createMarkers(instanceCount * groupCount) const counts = { drawCount: mesh.triangleCount * 3, groupCount, instanceCount } + const boundingSphere = calculateBoundingSphere( + mesh.vertexBuffer.ref.value, mesh.vertexCount, + transform.aTransform.ref.value, transform.instanceCount.ref.value + ) + return { aPosition: mesh.vertexBuffer, aNormal: mesh.normalBuffer, aGroup: mesh.groupBuffer, elements: mesh.indexBuffer, + boundingSphere: ValueCell.create(boundingSphere), ...color, ...marker, ...transform, @@ -370,6 +377,14 @@ export namespace Mesh { } export function updateValues(values: MeshValues, props: Props) { + const boundingSphere = calculateBoundingSphere( + values.aPosition.ref.value, Math.floor(values.aPosition.ref.value.length / 3), + values.aTransform.ref.value, values.instanceCount.ref.value + ) + if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) { + ValueCell.update(values.boundingSphere, boundingSphere) + } + Geometry.updateValues(values, props) ValueCell.updateIfChanged(values.dDoubleSided, props.doubleSided) ValueCell.updateIfChanged(values.dFlatShaded, props.flatShaded) diff --git a/src/mol-geo/geometry/points/points.ts b/src/mol-geo/geometry/points/points.ts index 7dce2416ff51a7e7c4309ad05a12caca0e728c9e..84a191bf7559f158dc926384f9d44200c4902270 100644 --- a/src/mol-geo/geometry/points/points.ts +++ b/src/mol-geo/geometry/points/points.ts @@ -7,7 +7,7 @@ import { ValueCell } from 'mol-util' import { Mat4 } from 'mol-math/linear-algebra' import { transformPositionArray/* , transformDirectionArray, getNormalMatrix */ } from '../../util'; -import { Geometry } from '../geometry'; +import { Geometry, Theme } from '../geometry'; import { PointsValues } from 'mol-gl/renderable'; import { RuntimeContext } from 'mol-task'; import { createColors } from '../color-data'; @@ -15,8 +15,9 @@ import { createMarkers } from '../marker-data'; import { createSizes } from '../size-data'; import { TransformData } from '../transform-data'; import { LocationIterator } from '../../util/location-iterator'; -import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; import { ParamDefinition as PD } from 'mol-util/param-definition'; +import { calculateBoundingSphere } from 'mol-gl/renderable/util'; +import { Sphere3D } from 'mol-math/geometry'; /** Point cloud */ export interface Points { @@ -58,24 +59,27 @@ export namespace Points { pointSizeAttenuation: PD.Boolean('Point Size Attenuation', '', false), pointFilledCircle: PD.Boolean('Point Filled Circle', '', false), pointEdgeBleach: PD.Numeric('Point Edge Bleach', '', 0.2, 0, 1, 0.05), - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1), - sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1), } export const DefaultProps = PD.getDefaultValues(Params) export type Props = typeof DefaultProps - export async function createValues(ctx: RuntimeContext, points: Points, transform: TransformData, locationIt: LocationIterator, props: Props): Promise<PointsValues> { + export async function createValues(ctx: RuntimeContext, points: Points, transform: TransformData, locationIt: LocationIterator, theme: Theme, props: Props): Promise<PointsValues> { const { instanceCount, groupCount } = locationIt - const color = await createColors(ctx, locationIt, props) - const size = await createSizes(ctx, locationIt, props) + const color = await createColors(ctx, locationIt, theme.color) + const size = await createSizes(ctx, locationIt, theme.size) const marker = createMarkers(instanceCount * groupCount) const counts = { drawCount: points.pointCount, groupCount, instanceCount } + const boundingSphere = calculateBoundingSphere( + points.centerBuffer.ref.value, points.pointCount, + transform.aTransform.ref.value, transform.instanceCount.ref.value + ) + return { aPosition: points.centerBuffer, aGroup: points.groupBuffer, + boundingSphere: ValueCell.create(boundingSphere), ...color, ...size, ...marker, @@ -89,6 +93,14 @@ export namespace Points { } export function updateValues(values: PointsValues, props: Props) { + const boundingSphere = calculateBoundingSphere( + values.aPosition.ref.value, Math.floor(values.aPosition.ref.value.length / 3), + values.aTransform.ref.value, values.instanceCount.ref.value + ) + if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) { + ValueCell.update(values.boundingSphere, boundingSphere) + } + Geometry.updateValues(values, props) ValueCell.updateIfChanged(values.dPointSizeAttenuation, props.pointSizeAttenuation) ValueCell.updateIfChanged(values.dPointFilledCircle, props.pointFilledCircle) diff --git a/src/mol-geo/geometry/size-data.ts b/src/mol-geo/geometry/size-data.ts index 7c7ab279493648eb0aa05f5fa7ac184d31c4b387..06cdcef0c6d48ef6d47a333bf9fc58edb3eb14c1 100644 --- a/src/mol-geo/geometry/size-data.ts +++ b/src/mol-geo/geometry/size-data.ts @@ -40,8 +40,7 @@ export function getSizeThemeProps(props: SizeProps): SizeThemeProps { } } -export async function createSizes(ctx: RuntimeContext, locationIt: LocationIterator, props: SizeProps, sizeData?: SizeData): Promise<SizeData> { - const sizeTheme = SizeTheme(getSizeThemeProps(props)) +export async function createSizes(ctx: RuntimeContext, locationIt: LocationIterator, sizeTheme: SizeTheme, sizeData?: SizeData): Promise<SizeData> { switch (getGranularity(locationIt, sizeTheme.granularity)) { case 'uniform': return createUniformSize(ctx, locationIt, sizeTheme.size, sizeData) case 'group': return createGroupSize(ctx, locationIt, sizeTheme.size, sizeData) diff --git a/src/mol-gl/_spec/renderer.spec.ts b/src/mol-gl/_spec/renderer.spec.ts index 6ede20f9997f0ea08e4b64b06dc1dacb73883dfc..b564c9076680c2eadeb846ec3cf44a2f65e815ea 100644 --- a/src/mol-gl/_spec/renderer.spec.ts +++ b/src/mol-gl/_spec/renderer.spec.ts @@ -21,6 +21,7 @@ import Scene from '../scene'; import { createEmptyMarkers } from 'mol-geo/geometry/marker-data'; import { fillSerial } from 'mol-util/array'; import { Color } from 'mol-util/color'; +import { Sphere3D } from 'mol-math/geometry'; // function writeImage(gl: WebGLRenderingContext, width: number, height: number) { // const pixels = new Uint8Array(width * height * 4) @@ -56,6 +57,8 @@ function createPoints() { const m4 = Mat4.identity() Mat4.toArray(m4, aTransform.ref.value, 0) + const boundingSphere = ValueCell.create(Sphere3D.create(Vec3.zero(), 2)) + const values: PointsValues = { aPosition, aGroup, @@ -71,6 +74,7 @@ function createPoints() { drawCount: ValueCell.create(3), instanceCount: ValueCell.create(1), + boundingSphere, dPointSizeAttenuation: ValueCell.create(true), dPointFilledCircle: ValueCell.create(false), diff --git a/src/mol-gl/renderable.ts b/src/mol-gl/renderable.ts index 1567603088c3853aec2a892b86a83188db54c62c..8512933e0d78e1beea97d2ba39da357f7bdf8322 100644 --- a/src/mol-gl/renderable.ts +++ b/src/mol-gl/renderable.ts @@ -8,8 +8,6 @@ import { Program } from './webgl/program'; import { RenderableValues, Values, RenderableSchema } from './renderable/schema'; import { RenderVariant, RenderItem } from './webgl/render-item'; import { Sphere3D } from 'mol-math/geometry'; -// import { calculateBoundingSphereFromValues } from './renderable/util'; -// import { Sphere } from 'mol-geo/primitive/sphere'; import { Vec3 } from 'mol-math/linear-algebra'; export type RenderableState = { @@ -30,29 +28,22 @@ export interface Renderable<T extends RenderableValues> { } export function createRenderable<T extends Values<RenderableSchema>>(renderItem: RenderItem, values: T, state: RenderableState): Renderable<T> { - // TODO let boundingSphere: Sphere3D = Sphere3D.create(Vec3.zero(), 50) return { get values () { return values }, get state () { return state }, get boundingSphere () { + if (values.boundingSphere) { + Sphere3D.copy(boundingSphere, values.boundingSphere.ref.value) + } return boundingSphere - // TODO - // if (boundingSphere) return boundingSphere - // boundingSphere = calculateBoundingSphereFromValues(values) - // return boundingSphere }, get opaque () { return values.uAlpha && values.uAlpha.ref.value === 1 }, render: (variant: RenderVariant) => renderItem.render(variant), getProgram: (variant: RenderVariant) => renderItem.getProgram(variant), - update: () => { - renderItem.update() - // TODO - // const valueChanges = renderItem.update() - // if (valueChanges.attributes) boundingSphere = undefined - }, + update: () => renderItem.update(), dispose: () => renderItem.destroy() } } diff --git a/src/mol-gl/renderable/direct-volume.ts b/src/mol-gl/renderable/direct-volume.ts index a27ec8edd8ad66f0065c9ddf2d2eafe14238357a..63b2424ed608744a5e6b6651d284b2a991a5412a 100644 --- a/src/mol-gl/renderable/direct-volume.ts +++ b/src/mol-gl/renderable/direct-volume.ts @@ -29,6 +29,7 @@ export const DirectVolumeSchema = { drawCount: ValueSpec('number'), instanceCount: ValueSpec('number'), + boundingSphere: ValueSpec('sphere'), aPosition: AttributeSpec('float32', 3, 0), elements: ElementsSpec('uint32'), diff --git a/src/mol-gl/renderable/schema.ts b/src/mol-gl/renderable/schema.ts index 0e5826819aece71768921e486e6402fdba701bf2..765f6dc2e237c9a383a5e8163f8b79e248436f54 100644 --- a/src/mol-gl/renderable/schema.ts +++ b/src/mol-gl/renderable/schema.ts @@ -11,11 +11,15 @@ import { DefineKind, DefineValues } from '../shader-code'; import { Vec2, Vec3, Vec4, Mat3, Mat4 } from 'mol-math/linear-algebra'; import { TextureImage, TextureVolume } from './util'; import { TextureValues, TextureType, TextureFormat, TextureFilter, TextureKind, Texture } from '../webgl/texture'; +import { Sphere3D } from 'mol-math/geometry'; export type ValueKindType = { 'number': number 'string': string + 'boolean': string 'any': any + + 'sphere': Sphere3D } export type ValueKind = keyof ValueKindType @@ -51,6 +55,8 @@ export type KindValue = { 'string': string 'boolean': boolean 'any': any + + 'sphere': Sphere3D } export type Values<S extends RenderableSchema> = { [k in keyof S]: ValueCell<KindValue[S[k]['kind']]> } @@ -192,6 +198,7 @@ export const BaseSchema = { drawCount: ValueSpec('number'), instanceCount: ValueSpec('number'), + boundingSphere: ValueSpec('sphere'), dUseFog: DefineSpec('boolean'), } diff --git a/src/mol-gl/scene.ts b/src/mol-gl/scene.ts index 8b995572d9fa6491a0b6eebf68d661f006a36399..1ef3fa81c32028813bea5d3d9e2fd805d9cf2930 100644 --- a/src/mol-gl/scene.ts +++ b/src/mol-gl/scene.ts @@ -56,7 +56,10 @@ namespace Scene { const object3d = Object3D.create() return { - ...object3d, + get view () { return object3d.view }, + get position () { return object3d.position }, + get direction () { return object3d.direction }, + get up () { return object3d.up }, update: () => { Object3D.update(object3d) @@ -103,7 +106,7 @@ namespace Scene { }, get boundingSphere() { if (boundingSphere) return boundingSphere - // TODO avoid array creation + // TODO avoid object creation boundingSphere = calculateBoundingSphere(renderableMap) return boundingSphere } diff --git a/src/mol-math/geometry/primitives/sphere3d.ts b/src/mol-math/geometry/primitives/sphere3d.ts index c38e9275a421d9935b913c028091c5e4370eb11d..380f3f5f2fdcc5fd7f63fdcf2e4193b820d9ca86 100644 --- a/src/mol-math/geometry/primitives/sphere3d.ts +++ b/src/mol-math/geometry/primitives/sphere3d.ts @@ -5,7 +5,7 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { Vec3, Mat4 } from '../../linear-algebra' +import { Vec3, Mat4, EPSILON } from '../../linear-algebra' import { PositionData } from '../common' import { OrderedSet } from 'mol-data/int'; @@ -15,6 +15,12 @@ namespace Sphere3D { export function create(center: Vec3, radius: number): Sphere3D { return { center, radius }; } export function zero(): Sphere3D { return { center: Vec3.zero(), radius: 0 }; } + export function copy(out: Sphere3D, a: Sphere3D) { + Vec3.copy(out.center, a.center) + out.radius = a.radius + return out; + } + export function computeBounding(data: PositionData): Sphere3D { const { x, y, z, indices } = data; let cx = 0, cy = 0, cz = 0; @@ -50,6 +56,39 @@ namespace Sphere3D { out.radius = sphere.radius * Mat4.getMaxScaleOnAxis(m) return out } + + export function toArray(s: Sphere3D, out: Helpers.NumberArray, offset: number) { + Vec3.toArray(s.center, out, offset) + out[offset + 3] = s.radius + } + + export function fromArray(out: Sphere3D, array: Helpers.NumberArray, offset: number) { + Vec3.fromArray(out.center, array, offset) + out.radius = array[offset + 3] + return out + } + + export function addSphere(out: Sphere3D, sphere: Sphere3D) { + out.radius = Math.max(out.radius, Vec3.distance(out.center, sphere.center) + sphere.radius) + return out + } + + /** + * Returns whether or not the spheres have exactly the same center and radius (when compared with ===) + */ + export function exactEquals(a: Sphere3D, b: Sphere3D) { + return a.radius === b.radius && Vec3.exactEquals(a.center, b.center); + } + + /** + * Returns whether or not the spheres have approximately the same center and radius. + */ + export function equals(a: Sphere3D, b: Sphere3D) { + const ar = a.radius; + const br = b.radius; + return (Math.abs(ar - br) <= EPSILON.Value * Math.max(1.0, Math.abs(ar), Math.abs(br)) && + Vec3.equals(a.center, b.center)); + } } export { Sphere3D } \ No newline at end of file diff --git a/src/mol-math/linear-algebra/3d/vec4.ts b/src/mol-math/linear-algebra/3d/vec4.ts index 00d682a1628b7f5c8a71820cb29d3e2cb045e3e9..db4f29c33c83b2809c6d58fa05d241cb020965d5 100644 --- a/src/mol-math/linear-algebra/3d/vec4.ts +++ b/src/mol-math/linear-algebra/3d/vec4.ts @@ -18,6 +18,7 @@ */ import Mat4 from './mat4'; +import { EPSILON } from '../3d'; interface Vec4 extends Array<number> { [d: number]: number, '@type': 'vec4', length: 4 } @@ -196,6 +197,25 @@ namespace Vec4 { out[3] = 1.0 / a[3]; return out; } + + /** + * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===) + */ + export function exactEquals(a: Vec4, b: Vec4) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]; + } + + /** + * Returns whether or not the vectors have approximately the same elements in the same position. + */ + export function equals(a: Vec4, b: Vec4) { + const a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; + const b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; + return (Math.abs(a0 - b0) <= EPSILON.Value * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && + Math.abs(a1 - b1) <= EPSILON.Value * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && + Math.abs(a2 - b2) <= EPSILON.Value * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && + Math.abs(a3 - b3) <= EPSILON.Value * Math.max(1.0, Math.abs(a3), Math.abs(b3))); + } } export default Vec4 \ No newline at end of file diff --git a/src/mol-repr/index.ts b/src/mol-repr/index.ts index 7b6beef01a1615ca63c69093367c81ac69154fbc..574bcb0b0e7055503383a8cea53d930798bfc9df 100644 --- a/src/mol-repr/index.ts +++ b/src/mol-repr/index.ts @@ -11,6 +11,8 @@ import { Loci, isEmptyLoci, EmptyLoci } from 'mol-model/loci'; import { MarkerAction } from '../mol-geo/geometry/marker-data'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { WebGLContext } from 'mol-gl/webgl/context'; +import { getQualityProps } from './util'; +import { Theme } from 'mol-geo/geometry/geometry'; // import { ColorTheme } from 'mol-theme/color'; // export interface RepresentationProps { @@ -68,9 +70,8 @@ export namespace Representation { }, createOrUpdate: (ctx: RepresentationContext, props: Partial<P> = {}, data?: D) => { if (data) currentData = data - // const qualityProps = getQualityProps(Object.assign({}, currentProps, props), structure) - // currentProps = Object.assign({}, DefaultCartoonProps, currentProps, props, qualityProps) - currentProps = Object.assign({}, defaultProps, currentProps, props) + const qualityProps = getQualityProps(Object.assign({}, currentProps, props), data) + currentProps = Object.assign({}, defaultProps, currentProps, props, qualityProps) const { visuals } = currentProps return Task.create(`Creating '${label}' representation`, async runtime => { @@ -108,13 +109,11 @@ export namespace Representation { export interface VisualContext extends RepresentationContext { runtime: RuntimeContext, - // TODO - // colorTheme: ColorTheme, } export interface Visual<D, P extends RepresentationProps> { readonly renderObject: RenderObject | undefined - createOrUpdate: (ctx: VisualContext, props?: Partial<P>, data?: D) => Promise<void> + createOrUpdate: (ctx: VisualContext, theme: Theme, props?: Partial<P>, data?: D) => Promise<void> getLoci: (pickingId: PickingId) => Loci mark: (loci: Loci, action: MarkerAction) => boolean destroy: () => void diff --git a/src/mol-repr/shape/index.ts b/src/mol-repr/shape/index.ts index 46fbeb495c9116c566d06835406a12243635a36e..ee22bdf32dd6add15d5ab4a1e5ed9b93bb3904b9 100644 --- a/src/mol-repr/shape/index.ts +++ b/src/mol-repr/shape/index.ts @@ -15,7 +15,7 @@ import { OrderedSet, Interval } from 'mol-data/int'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { createIdentityTransform } from 'mol-geo/geometry/transform-data'; -import { createRenderableState } from 'mol-geo/geometry/geometry'; +import { createRenderableState, createTheme } from 'mol-geo/geometry/geometry'; import { PickingId } from 'mol-geo/geometry/picking'; import { MarkerAction, applyMarkerAction } from 'mol-geo/geometry/marker-data'; import { LocationIterator } from 'mol-geo/util/location-iterator'; @@ -49,9 +49,10 @@ export function ShapeRepresentation<P extends ShapeProps>(): ShapeRepresentation const mesh = _shape.mesh const locationIt = ShapeGroupIterator.fromShape(_shape) + const theme = createTheme(currentProps) const transform = createIdentityTransform() - const values = await Mesh.createValues(runtime, mesh, transform, locationIt, currentProps) + const values = await Mesh.createValues(runtime, mesh, transform, locationIt, theme, currentProps) const state = createRenderableState(currentProps) _renderObject = createMeshRenderObject(values, state) diff --git a/src/mol-repr/structure/complex-representation.ts b/src/mol-repr/structure/complex-representation.ts index 62d828bb2c0d8b783c8c87dd58c21dd1eaefe374..58529f5dd1b6c43a45a5ace7b7f01a0544052ea2 100644 --- a/src/mol-repr/structure/complex-representation.ts +++ b/src/mol-repr/structure/complex-representation.ts @@ -13,17 +13,22 @@ import { ComplexVisual } from './complex-visual'; import { PickingId } from 'mol-geo/geometry/picking'; import { MarkerAction } from 'mol-geo/geometry/marker-data'; import { RepresentationContext } from 'mol-repr'; +import { createTheme, Theme } from 'mol-geo/geometry/geometry'; export function ComplexRepresentation<P extends StructureProps>(label: string, visualCtor: () => ComplexVisual<P>): StructureRepresentation<P> { let visual: ComplexVisual<P> | undefined + let _structure: Structure let _props: P + let _theme: Theme function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, structure?: Structure) { - _props = Object.assign({}, _props, props) + if (structure) _structure = structure + _props = Object.assign({}, _props, props, { structure: _structure }) + _theme = createTheme(_props) return Task.create('Creating or updating ComplexRepresentation', async runtime => { if (!visual) visual = visualCtor() - await visual.createOrUpdate({ ...ctx, runtime }, _props, structure) + await visual.createOrUpdate({ ...ctx, runtime }, _theme, _props, structure) }); } diff --git a/src/mol-repr/structure/complex-visual.ts b/src/mol-repr/structure/complex-visual.ts index 8a5a4611f4a6c41bc48a49a83bd84fcc77465bcd..4440129f999ebde9726e73d8ada58117e3db3743 100644 --- a/src/mol-repr/structure/complex-visual.ts +++ b/src/mol-repr/structure/complex-visual.ts @@ -15,7 +15,7 @@ import { Interval } from 'mol-data/int'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { RenderableValues } from 'mol-gl/renderable/schema'; import { createSizes } from 'mol-geo/geometry/size-data'; -import { Geometry, updateRenderableState } from 'mol-geo/geometry/geometry'; +import { Geometry, updateRenderableState, Theme } from 'mol-geo/geometry/geometry'; import { LocationIterator } from 'mol-geo/util/location-iterator'; import { PickingId } from 'mol-geo/geometry/picking'; import { createColors } from 'mol-geo/geometry/color-data'; @@ -36,7 +36,7 @@ type ComplexRenderObject = MeshRenderObject | LinesRenderObject | PointsRenderOb interface ComplexVisualBuilder<P extends ComplexProps, G extends Geometry> { defaultProps: P - createGeometry(ctx: VisualContext, structure: Structure, props: P, geometry?: G): Promise<G> + createGeometry(ctx: VisualContext, structure: Structure, theme: Theme, props: P, geometry?: G): Promise<G> createLocationIterator(structure: Structure): LocationIterator getLoci(pickingId: PickingId, structure: Structure, id: number): Loci mark(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean): boolean, @@ -45,7 +45,7 @@ interface ComplexVisualBuilder<P extends ComplexProps, G extends Geometry> { interface ComplexVisualGeometryBuilder<P extends ComplexProps, G extends Geometry> extends ComplexVisualBuilder<P, G> { createEmptyGeometry(geometry?: G): G - createRenderObject(ctx: VisualContext, structure: Structure, geometry: Geometry, locationIt: LocationIterator, currentProps: P): Promise<ComplexRenderObject> + createRenderObject(ctx: VisualContext, structure: Structure, geometry: Geometry, locationIt: LocationIterator, theme: Theme, currentProps: P): Promise<ComplexRenderObject> updateValues(values: RenderableValues, newProps: P): void } @@ -61,18 +61,18 @@ export function ComplexVisual<P extends ComplexMeshProps>(builder: ComplexVisual let locationIt: LocationIterator let conformationHash: number - async function create(ctx: VisualContext, structure: Structure, props: Partial<P> = {}) { - currentProps = Object.assign({}, defaultProps, props, { structure }) + async function create(ctx: VisualContext, structure: Structure, theme: Theme, props: Partial<P> = {}) { + currentProps = Object.assign({}, defaultProps, props) currentStructure = structure conformationHash = Structure.conformationHash(currentStructure) - geometry = await createGeometry(ctx, currentStructure, currentProps, geometry) + geometry = await createGeometry(ctx, currentStructure, theme, currentProps, geometry) locationIt = createLocationIterator(structure) - renderObject = await createRenderObject(ctx, structure, geometry, locationIt, currentProps) + renderObject = await createRenderObject(ctx, structure, geometry, locationIt, theme, currentProps) } - async function update(ctx: VisualContext, props: Partial<P>) { + async function update(ctx: VisualContext, theme: Theme, props: Partial<P>) { const newProps = Object.assign({}, currentProps, props, { structure: currentStructure }) if (!renderObject) return false @@ -93,7 +93,7 @@ export function ComplexVisual<P extends ComplexMeshProps>(builder: ComplexVisual // if (updateState.createGeometry) { - geometry = await createGeometry(ctx, currentStructure, newProps, geometry) + geometry = await createGeometry(ctx, currentStructure, theme, newProps, geometry) ValueCell.update(renderObject.values.drawCount, Geometry.getDrawCount(geometry)) updateState.updateColor = true } @@ -101,12 +101,12 @@ export function ComplexVisual<P extends ComplexMeshProps>(builder: ComplexVisual if (updateState.updateSize) { // not all geometries have size data, so check here if ('uSize' in renderObject.values) { - await createSizes(ctx.runtime, locationIt, newProps, renderObject.values) + await createSizes(ctx.runtime, locationIt, theme.size, renderObject.values) } } if (updateState.updateColor) { - await createColors(ctx.runtime, locationIt, newProps, renderObject.values) + await createColors(ctx.runtime, locationIt, theme.color, renderObject.values) } updateValues(renderObject.values, newProps) @@ -118,18 +118,18 @@ export function ComplexVisual<P extends ComplexMeshProps>(builder: ComplexVisual return { get renderObject () { return renderObject }, - async createOrUpdate(ctx: VisualContext, props: Partial<P> = {}, structure?: Structure) { + async createOrUpdate(ctx: VisualContext, theme: Theme, props: Partial<P> = {}, structure?: Structure) { if (!structure && !currentStructure) { throw new Error('missing structure') } else if (structure && (!currentStructure || !renderObject)) { - await create(ctx, structure, props) + await create(ctx, structure, theme, props) } else if (structure && structure.hashCode !== currentStructure.hashCode) { - await create(ctx, structure, props) + await create(ctx, structure, theme, props) } else { if (structure && Structure.conformationHash(structure) !== Structure.conformationHash(currentStructure)) { currentStructure = structure } - await update(ctx, props) + await update(ctx, theme, props) } }, getLoci(pickingId: PickingId) { diff --git a/src/mol-repr/structure/representation/cartoon.ts b/src/mol-repr/structure/representation/cartoon.ts index dbf44633d96ac07a858b220d1f03f7f0423a5a06..59e0639758375d2600943412da45f82a8ef3a2e2 100644 --- a/src/mol-repr/structure/representation/cartoon.ts +++ b/src/mol-repr/structure/representation/cartoon.ts @@ -12,17 +12,17 @@ import { ParamDefinition as PD } from 'mol-util/param-definition'; import { UnitsRepresentation } from '../units-representation'; import { StructureRepresentation } from '../index'; import { Representation } from 'mol-repr'; -// import { PolymerDirectionVisual, DefaultPolymerDirectionProps } from '../visual/polymer-direction-wedge'; +import { PolymerDirectionVisual, PolymerDirectionParams } from '../visual/polymer-direction-wedge'; export const CartoonParams = { ...PolymerTraceParams, ...PolymerGapParams, ...NucleotideBlockParams, - // ...PolymerDirectionParams, + ...PolymerDirectionParams, sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 0.6, 0, 10, 0.1), + sizeValue: PD.Numeric('Size Value', '', 0.2, 0, 10, 0.1), } -export const DefaultCartoonProps = PD.getDefaultValues(CartoonParams) +export const DefaultCartoonProps = { ...PD.getDefaultValues(CartoonParams), visuals: [ '0', '1', '2' ] } export type CartoonProps = typeof DefaultCartoonProps export type CartoonRepresentation = StructureRepresentation<CartoonProps> @@ -32,6 +32,6 @@ export function CartoonRepresentation(): CartoonRepresentation { UnitsRepresentation('Polymer trace mesh', PolymerTraceVisual), UnitsRepresentation('Polymer gap cylinder', PolymerGapVisual), UnitsRepresentation('Nucleotide block mesh', NucleotideBlockVisual), - // UnitsRepresentation('Polymer direction wedge', PolymerDirectionVisual) - ] as StructureRepresentation<CartoonProps>[]) + UnitsRepresentation('Polymer direction wedge', PolymerDirectionVisual) + ] as unknown as StructureRepresentation<CartoonProps>[]) // TODO avoid cast to unknown } \ No newline at end of file diff --git a/src/mol-repr/structure/units-representation.ts b/src/mol-repr/structure/units-representation.ts index 50e350f5cbef9a0c40fec28635278495f8fbc30e..0b419bc140e3a411bbc0c24c4aa5617ce4e4aaba 100644 --- a/src/mol-repr/structure/units-representation.ts +++ b/src/mol-repr/structure/units-representation.ts @@ -14,6 +14,7 @@ import { StructureGroup } from './units-visual'; import { StructureProps, StructureParams, StructureRepresentation } from './index'; import { PickingId } from 'mol-geo/geometry/picking'; import { MarkerAction } from 'mol-geo/geometry/marker-data'; +import { Theme, createTheme } from 'mol-geo/geometry/geometry'; export interface UnitsVisual<P extends RepresentationProps = {}> extends Visual<StructureGroup, P> { } @@ -21,11 +22,13 @@ export function UnitsRepresentation<P extends StructureProps>(label: string, vis let visuals = new Map<number, { group: Unit.SymmetryGroup, visual: UnitsVisual<P> }>() let _props: P + let _theme: Theme let _structure: Structure let _groups: ReadonlyArray<Unit.SymmetryGroup> function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, structure?: Structure) { - _props = Object.assign({}, _props, props) + _props = Object.assign({}, _props, props, { structure: structure || _structure }) + _theme = createTheme(_props) return Task.create('Creating or updating UnitsRepresentation', async runtime => { if (!_structure && !structure) { @@ -37,7 +40,7 @@ export function UnitsRepresentation<P extends StructureProps>(label: string, vis for (let i = 0; i < _groups.length; i++) { const group = _groups[i]; const visual = visualCtor() - await visual.createOrUpdate({ ...ctx, runtime }, _props, { group, structure }) + await visual.createOrUpdate({ ...ctx, runtime }, _theme, _props, { group, structure }) visuals.set(group.hashCode, { visual, group }) } } else if (structure && _structure.hashCode !== structure.hashCode) { @@ -53,13 +56,13 @@ export function UnitsRepresentation<P extends StructureProps>(label: string, vis const visualGroup = oldVisuals.get(group.hashCode) if (visualGroup) { const { visual } = visualGroup - await visual.createOrUpdate({ ...ctx, runtime }, _props, { group, structure }) + await visual.createOrUpdate({ ...ctx, runtime }, _theme, _props, { group, structure }) visuals.set(group.hashCode, { visual, group }) oldVisuals.delete(group.hashCode) } else { // newGroups.push(group) const visual = visualCtor() - await visual.createOrUpdate({ ...ctx, runtime }, _props, { group, structure }) + await visual.createOrUpdate({ ...ctx, runtime }, _theme, _props, { group, structure }) visuals.set(group.hashCode, { visual, group }) } } @@ -85,7 +88,7 @@ export function UnitsRepresentation<P extends StructureProps>(label: string, vis const group = _groups[i]; const visualGroup = visuals.get(group.hashCode) if (visualGroup) { - await visualGroup.visual.createOrUpdate({ ...ctx, runtime }, _props, { group, structure }) + await visualGroup.visual.createOrUpdate({ ...ctx, runtime }, _theme, _props, { group, structure }) visualGroup.group = group } else { throw new Error(`expected to find visual for hashCode ${group.hashCode}`) @@ -98,7 +101,7 @@ export function UnitsRepresentation<P extends StructureProps>(label: string, vis visuals.forEach(({ visual, group }) => visualsList.push([ visual, group ])) for (let i = 0, il = visualsList.length; i < il; ++i) { const [ visual, group ] = visualsList[i] - await visual.createOrUpdate({ ...ctx, runtime }, _props, { group, structure: _structure }) + await visual.createOrUpdate({ ...ctx, runtime }, _theme, _props, { group, structure: _structure }) } } if (structure) _structure = structure diff --git a/src/mol-repr/structure/units-visual.ts b/src/mol-repr/structure/units-visual.ts index bdb96e7165d62187963c9c2f15bb57e97cb92685..c4c8e856418fb1cc91790c6ea96de193c6c7f9d9 100644 --- a/src/mol-repr/structure/units-visual.ts +++ b/src/mol-repr/structure/units-visual.ts @@ -14,7 +14,7 @@ import { deepEqual, ValueCell, UUID } from 'mol-util'; import { Interval } from 'mol-data/int'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { RenderableValues } from 'mol-gl/renderable/schema'; -import { Geometry, updateRenderableState } from 'mol-geo/geometry/geometry'; +import { Geometry, updateRenderableState, Theme } from 'mol-geo/geometry/geometry'; import { LocationIterator } from 'mol-geo/util/location-iterator'; import { PickingId } from 'mol-geo/geometry/picking'; import { createMarkers, MarkerAction, applyMarkerAction } from 'mol-geo/geometry/marker-data'; @@ -48,7 +48,7 @@ type UnitsRenderObject = MeshRenderObject | LinesRenderObject | PointsRenderObje interface UnitsVisualBuilder<P extends UnitsProps, G extends Geometry> { defaultProps: P - createGeometry(ctx: VisualContext, unit: Unit, structure: Structure, props: P, geometry?: G): Promise<G> + createGeometry(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: P, geometry?: G): Promise<G> createLocationIterator(group: Unit.SymmetryGroup): LocationIterator getLoci(pickingId: PickingId, group: Unit.SymmetryGroup, id: number): Loci mark(loci: Loci, group: Unit.SymmetryGroup, apply: (interval: Interval) => boolean): boolean @@ -57,7 +57,7 @@ interface UnitsVisualBuilder<P extends UnitsProps, G extends Geometry> { interface UnitsVisualGeometryBuilder<P extends UnitsProps, G extends Geometry> extends UnitsVisualBuilder<P, G> { createEmptyGeometry(geometry?: G): G - createRenderObject(ctx: VisualContext, group: Unit.SymmetryGroup, geometry: Geometry, locationIt: LocationIterator, currentProps: P): Promise<UnitsRenderObject> + createRenderObject(ctx: VisualContext, group: Unit.SymmetryGroup, geometry: Geometry, locationIt: LocationIterator, theme: Theme, currentProps: P): Promise<UnitsRenderObject> updateValues(values: RenderableValues, newProps: P): void } @@ -74,22 +74,22 @@ export function UnitsVisual<P extends UnitsProps>(builder: UnitsVisualGeometryBu let locationIt: LocationIterator let currentConformationId: UUID - async function create(ctx: VisualContext, group: Unit.SymmetryGroup, props: Partial<P> = {}) { + async function create(ctx: VisualContext, group: Unit.SymmetryGroup, theme: Theme, props: Partial<P> = {}) { currentProps = Object.assign({}, defaultProps, props, { structure: currentStructure }) currentGroup = group const unit = group.units[0] currentConformationId = Unit.conformationId(unit) geometry = includesUnitKind(currentProps.unitKinds, unit) - ? await createGeometry(ctx, unit, currentStructure, currentProps, geometry) + ? await createGeometry(ctx, unit, currentStructure, theme, currentProps, geometry) : createEmptyGeometry(geometry) // TODO create empty location iterator when not in unitKinds locationIt = createLocationIterator(group) - renderObject = await createRenderObject(ctx, group, geometry, locationIt, currentProps) + renderObject = await createRenderObject(ctx, group, geometry, locationIt, theme, currentProps) } - async function update(ctx: VisualContext, props: Partial<P> = {}) { + async function update(ctx: VisualContext, theme: Theme, props: Partial<P> = {}) { if (!renderObject) return const newProps = Object.assign({}, currentProps, props, { structure: currentStructure }) @@ -122,7 +122,7 @@ export function UnitsVisual<P extends UnitsProps>(builder: UnitsVisualGeometryBu if (updateState.createGeometry) { geometry = includesUnitKind(newProps.unitKinds, unit) - ? await createGeometry(ctx, unit, currentStructure, newProps, geometry) + ? await createGeometry(ctx, unit, currentStructure, theme, newProps, geometry) : createEmptyGeometry(geometry) ValueCell.update(renderObject.values.drawCount, Geometry.getDrawCount(geometry)) updateState.updateColor = true @@ -131,12 +131,12 @@ export function UnitsVisual<P extends UnitsProps>(builder: UnitsVisualGeometryBu if (updateState.updateSize) { // not all geometries have size data, so check here if ('uSize' in renderObject.values) { - await createSizes(ctx.runtime, locationIt, newProps, renderObject.values) + await createSizes(ctx.runtime, locationIt, theme.size, renderObject.values) } } if (updateState.updateColor) { - await createColors(ctx.runtime, locationIt, newProps, renderObject.values) + await createColors(ctx.runtime, locationIt, theme.color, renderObject.values) } updateValues(renderObject.values, newProps) @@ -147,24 +147,24 @@ export function UnitsVisual<P extends UnitsProps>(builder: UnitsVisualGeometryBu return { get renderObject () { return renderObject }, - async createOrUpdate(ctx: VisualContext, props: Partial<P> = {}, structureGroup?: StructureGroup) { + async createOrUpdate(ctx: VisualContext, theme: Theme, props: Partial<P> = {}, structureGroup?: StructureGroup) { if (structureGroup) currentStructure = structureGroup.structure const group = structureGroup ? structureGroup.group : undefined if (!group && !currentGroup) { throw new Error('missing group') } else if (group && (!currentGroup || !renderObject)) { // console.log('unit-visual first create') - await create(ctx, group, props) + await create(ctx, group, theme, props) } else if (group && group.hashCode !== currentGroup.hashCode) { // console.log('unit-visual group.hashCode !== currentGroup.hashCode') - await create(ctx, group, props) + await create(ctx, group, theme, props) } else { // console.log('unit-visual update') if (group && !sameGroupConformation(group, currentGroup)) { // console.log('unit-visual new conformation') currentGroup = group } - await update(ctx, props) + await update(ctx, theme, props) } }, getLoci(pickingId: PickingId) { diff --git a/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts b/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts index 5db9028b2c7d5f0a537af8989b626a52e3b5354a..f4c555c956078e76575eb239a31b503fd4ce9e03 100644 --- a/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts +++ b/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts @@ -10,7 +10,7 @@ import { Vec3 } from 'mol-math/linear-algebra'; import { createLinkCylinderMesh, LinkCylinderProps, LinkCylinderParams } from './util/link'; import { OrderedSet, Interval } from 'mol-data/int'; import { ComplexMeshVisual, ComplexVisual } from '../complex-visual'; -import { SizeTheme, SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; +import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; import { LinkType } from 'mol-model/structure/model/types'; import { BitFlags } from 'mol-util'; import { UnitsMeshParams } from '../units-visual'; @@ -20,6 +20,7 @@ import { LocationIterator } from 'mol-geo/util/location-iterator'; import { PickingId } from 'mol-geo/geometry/picking'; import { VisualUpdateState } from '../../util'; import { VisualContext } from 'mol-repr'; +import { Theme } from 'mol-geo/geometry/geometry'; // TODO create seperate visual // for (let i = 0, il = carbohydrates.terminalLinks.length; i < il; ++i) { @@ -35,9 +36,8 @@ import { VisualContext } from 'mol-repr'; const radiusFactor = 0.3 -async function createCarbohydrateLinkCylinderMesh(ctx: VisualContext, structure: Structure, props: LinkCylinderProps, mesh?: Mesh) { +async function createCarbohydrateLinkCylinderMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: LinkCylinderProps, mesh?: Mesh) { const { links, elements } = structure.carbohydrates - const sizeTheme = SizeTheme({ name: props.sizeTheme, value: props.sizeValue }) const location = StructureElement.create() const builderProps = { @@ -54,7 +54,7 @@ async function createCarbohydrateLinkCylinderMesh(ctx: VisualContext, structure: const l = links[edgeIndex] location.unit = elements[l.carbohydrateIndexA].unit location.element = elements[l.carbohydrateIndexA].anomericCarbon - return sizeTheme.size(location) * radiusFactor + return theme.size.size(location) * radiusFactor } } diff --git a/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts b/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts index d4345c8bdcc363d65fc27359f21714ce222e3f6b..4c7597b923640c14c104005990c842802ad9637e 100644 --- a/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts +++ b/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts @@ -13,7 +13,7 @@ import { DiamondPrism, PentagonalPrism, HexagonalPrism } from 'mol-geo/primitive import { Structure, StructureElement } from 'mol-model/structure'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; -import { SizeTheme, SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; +import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; import { getSaccharideShape, SaccharideShapes } from 'mol-model/structure/structure/carbohydrates/constants'; import { addSphere } from 'mol-geo/geometry/mesh/builder/sphere'; import { ComplexMeshParams, ComplexMeshVisual } from '../complex-visual'; @@ -25,6 +25,7 @@ import { PickingId } from 'mol-geo/geometry/picking'; import { OrderedSet, Interval } from 'mol-data/int'; import { EmptyLoci, Loci } from 'mol-model/loci'; import { VisualContext } from 'mol-repr'; +import { Theme } from 'mol-geo/geometry/geometry'; const t = Mat4.identity() const sVec = Vec3.zero() @@ -44,10 +45,9 @@ const diamondPrism = DiamondPrism() const pentagonalPrism = PentagonalPrism() const hexagonalPrism = HexagonalPrism() -async function createCarbohydrateSymbolMesh(ctx: VisualContext, structure: Structure, props: CarbohydrateSymbolProps, mesh?: Mesh) { +async function createCarbohydrateSymbolMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: CarbohydrateSymbolProps, mesh?: Mesh) { const builder = MeshBuilder.create(256, 128, mesh) - const sizeTheme = SizeTheme({ name: props.sizeTheme, value: props.sizeValue }) const { detail } = props const carbohydrates = structure.carbohydrates @@ -60,7 +60,7 @@ async function createCarbohydrateSymbolMesh(ctx: VisualContext, structure: Struc l.unit = c.unit l.element = c.unit.elements[c.anomericCarbon] - const size = sizeTheme.size(l) + const size = theme.size.size(l) const radius = size * radiusFactor const side = size * sideFactor diff --git a/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts b/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts index 0beec07c39a27e975b770155cb87d6f18bd963c3..ff1c7e3b7953624e859b1feed1b4114e0b08caba 100644 --- a/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts +++ b/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts @@ -12,7 +12,7 @@ import { Vec3 } from 'mol-math/linear-algebra'; import { Loci, EmptyLoci } from 'mol-model/loci'; import { ComplexMeshVisual, ComplexMeshParams } from '../complex-visual'; import { Interval } from 'mol-data/int'; -import { SizeTheme, SizeThemeOptions, SizeThemeName } from 'mol-theme/size'; +import { SizeThemeOptions, SizeThemeName } from 'mol-theme/size'; import { BitFlags } from 'mol-util'; import { LinkType } from 'mol-model/structure/model/types'; import { ParamDefinition as PD } from 'mol-util/param-definition'; @@ -20,13 +20,13 @@ import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { LocationIterator } from 'mol-geo/util/location-iterator'; import { PickingId } from 'mol-geo/geometry/picking'; import { VisualContext } from 'mol-repr'; +import { Theme } from 'mol-geo/geometry/geometry'; -async function createCrossLinkRestraintCylinderMesh(ctx: VisualContext, structure: Structure, props: LinkCylinderProps, mesh?: Mesh) { +async function createCrossLinkRestraintCylinderMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: LinkCylinderProps, mesh?: Mesh) { const crossLinks = structure.crossLinkRestraints if (!crossLinks.count) return Mesh.createEmpty(mesh) - const sizeTheme = SizeTheme({ name: props.sizeTheme, value: props.sizeValue }) const location = StructureElement.create() const builderProps = { @@ -44,7 +44,7 @@ async function createCrossLinkRestraintCylinderMesh(ctx: VisualContext, structur const b = crossLinks.pairs[edgeIndex] location.unit = b.unitA location.element = b.unitA.elements[b.indexA] - return sizeTheme.size(location) + return theme.size.size(location) } } diff --git a/src/mol-repr/structure/visual/element-point.ts b/src/mol-repr/structure/visual/element-point.ts index 912c2f98dbd340000ccf8b687489dd908f967f66..6747ae9f889c15f9fcbdc2af94ad71b8cea30241 100644 --- a/src/mol-repr/structure/visual/element-point.ts +++ b/src/mol-repr/structure/visual/element-point.ts @@ -15,6 +15,7 @@ import { ParamDefinition as PD } from 'mol-util/param-definition'; import { Points } from 'mol-geo/geometry/points/points'; import { PointsBuilder } from 'mol-geo/geometry/points/points-builder'; import { VisualContext } from 'mol-repr'; +import { Theme } from 'mol-geo/geometry/geometry'; export const ElementPointParams = { ...UnitsPointsParams, @@ -27,7 +28,7 @@ export type ElementPointProps = typeof DefaultElementPointProps // TODO size -export async function createElementPoint(ctx: VisualContext, unit: Unit, structure: Structure, props: ElementPointProps, points: Points) { +export async function createElementPoint(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: ElementPointProps, points: Points) { const elements = unit.elements const n = elements.length const builder = PointsBuilder.create(n, n / 10, points) diff --git a/src/mol-repr/structure/visual/gaussian-density-point.ts b/src/mol-repr/structure/visual/gaussian-density-point.ts index 19372420f3413768a3d743a217427f3de6958233..5fd0069f1d7482b63d89baf3118d13b966a72781 100644 --- a/src/mol-repr/structure/visual/gaussian-density-point.ts +++ b/src/mol-repr/structure/visual/gaussian-density-point.ts @@ -17,6 +17,7 @@ import { ParamDefinition as PD } from 'mol-util/param-definition'; import { Points } from 'mol-geo/geometry/points/points'; import { PointsBuilder } from 'mol-geo/geometry/points/points-builder'; import { VisualContext } from 'mol-repr'; +import { Theme } from 'mol-geo/geometry/geometry'; export const GaussianDensityPointParams = { ...UnitsPointsParams, @@ -28,7 +29,7 @@ export const GaussianDensityPointParams = { export const DefaultGaussianDensityPointProps = PD.getDefaultValues(GaussianDensityPointParams) export type GaussianDensityPointProps = typeof DefaultGaussianDensityPointProps -export async function createGaussianDensityPoint(ctx: VisualContext, unit: Unit, structure: Structure, props: GaussianDensityProps, points?: Points) { +export async function createGaussianDensityPoint(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: GaussianDensityProps, points?: Points) { const { transform, field: { space, data } } = await unit.computeGaussianDensity(props, ctx.runtime, ctx.webgl) const { dimensions, get } = space diff --git a/src/mol-repr/structure/visual/gaussian-density-volume.ts b/src/mol-repr/structure/visual/gaussian-density-volume.ts index 90cc0f72fbae0b755f58c5971e18f00dd3da4fee..89f8b90f0f191a0201e72288c454ffe1c892bdc5 100644 --- a/src/mol-repr/structure/visual/gaussian-density-volume.ts +++ b/src/mol-repr/structure/visual/gaussian-density-volume.ts @@ -13,8 +13,9 @@ import { GaussianDensityProps, GaussianDensityParams, computeUnitGaussianDensity import { ParamDefinition as PD } from 'mol-util/param-definition'; import { DirectVolume } from 'mol-geo/geometry/direct-volume/direct-volume'; import { VisualContext } from 'mol-repr'; +import { Theme } from 'mol-geo/geometry/geometry'; -async function createGaussianDensityVolume(ctx: VisualContext, unit: Unit, structure: Structure, props: GaussianDensityProps, directVolume?: DirectVolume): Promise<DirectVolume> { +async function createGaussianDensityVolume(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: GaussianDensityProps, directVolume?: DirectVolume): Promise<DirectVolume> { const { runtime, webgl } = ctx if (webgl === undefined) throw new Error('createGaussianDensityVolume requires `webgl` object in VisualContext') diff --git a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts index e09ceaec17941e50e15a45457458174b923d175d..185cc9a3ce9e89a88755fd0c64d9093378016df6 100644 --- a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts +++ b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts @@ -14,8 +14,9 @@ import { ParamDefinition as PD } from 'mol-util/param-definition'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { computeMarchingCubesMesh } from 'mol-geo/util/marching-cubes/algorithm'; import { VisualContext } from 'mol-repr'; +import { Theme } from 'mol-geo/geometry/geometry'; -async function createGaussianSurfaceMesh(ctx: VisualContext, unit: Unit, structure: Structure, props: GaussianDensityProps, mesh?: Mesh): Promise<Mesh> { +async function createGaussianSurfaceMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: GaussianDensityProps, mesh?: Mesh): Promise<Mesh> { const { smoothness } = props const { transform, field, idField } = await unit.computeGaussianDensity(props, ctx.runtime, ctx.webgl) diff --git a/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts b/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts index 3f98da10bf835ae1d5d6b1dd87dedbaed0ef816c..b8f0d342e21e49c6743fc60945471b7725d865c8 100644 --- a/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts +++ b/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts @@ -15,8 +15,9 @@ import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; import { Lines } from 'mol-geo/geometry/lines/lines'; import { computeMarchingCubesLines } from 'mol-geo/util/marching-cubes/algorithm'; import { VisualContext } from 'mol-repr'; +import { Theme } from 'mol-geo/geometry/geometry'; -async function createGaussianWireframe(ctx: VisualContext, unit: Unit, structure: Structure, props: GaussianDensityProps, lines?: Lines): Promise<Lines> { +async function createGaussianWireframe(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: GaussianDensityProps, lines?: Lines): Promise<Lines> { const { smoothness } = props const { transform, field, idField } = await unit.computeGaussianDensity(props, ctx.runtime) diff --git a/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts b/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts index 71af78be00480229f117fd2c1410e1304e71b7d9..715e64e518e8cb79b5b1994da19d31f6ae5baec2 100644 --- a/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts +++ b/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts @@ -12,20 +12,19 @@ import { Vec3 } from 'mol-math/linear-algebra'; import { Loci, EmptyLoci } from 'mol-model/loci'; import { ComplexMeshVisual, ComplexMeshParams } from '../complex-visual'; import { Interval } from 'mol-data/int'; -import { SizeTheme, SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; import { BitFlags } from 'mol-util'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { PickingId } from 'mol-geo/geometry/picking'; import { VisualContext } from 'mol-repr'; +import { Theme } from 'mol-geo/geometry/geometry'; -async function createInterUnitLinkCylinderMesh(ctx: VisualContext, structure: Structure, props: LinkCylinderProps, mesh?: Mesh) { +async function createInterUnitLinkCylinderMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: LinkCylinderProps, mesh?: Mesh) { const links = structure.links const { bondCount, bonds } = links if (!bondCount) return Mesh.createEmpty(mesh) - const sizeTheme = SizeTheme({ name: props.sizeTheme, value: props.sizeValue, factor: props.sizeFactor }) const location = StructureElement.create() const builderProps = { @@ -43,7 +42,7 @@ async function createInterUnitLinkCylinderMesh(ctx: VisualContext, structure: St const b = bonds[edgeIndex] location.unit = b.unitA location.element = b.unitA.elements[b.indexA] - return sizeTheme.size(location) + return theme.size.size(location) } } @@ -53,9 +52,6 @@ async function createInterUnitLinkCylinderMesh(ctx: VisualContext, structure: St export const InterUnitLinkParams = { ...ComplexMeshParams, ...LinkCylinderParams, - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 0.2, 0, 10, 0.1), - sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1), } export const DefaultInterUnitLinkProps = PD.getDefaultValues(InterUnitLinkParams) export type InterUnitLinkProps = typeof DefaultInterUnitLinkProps diff --git a/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts b/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts index 546a389e7f789195ec10546abe0aa0cf9431ae52..ca5e2a295d119467190d9a166465ac49d1a1b32d 100644 --- a/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts +++ b/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts @@ -13,17 +13,17 @@ import { Vec3 } from 'mol-math/linear-algebra'; import { Loci, EmptyLoci } from 'mol-model/loci'; import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual'; import { Interval } from 'mol-data/int'; -import { SizeTheme, SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; +import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; import { BitFlags } from 'mol-util'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { PickingId } from 'mol-geo/geometry/picking'; import { VisualContext } from 'mol-repr'; +import { Theme } from 'mol-geo/geometry/geometry'; -async function createIntraUnitLinkCylinderMesh(ctx: VisualContext, unit: Unit, structure: Structure, props: LinkCylinderProps, mesh?: Mesh) { +async function createIntraUnitLinkCylinderMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: LinkCylinderProps, mesh?: Mesh) { if (!Unit.isAtomic(unit)) return Mesh.createEmpty(mesh) - const sizeTheme = SizeTheme({ name: props.sizeTheme, value: props.sizeValue, factor: props.sizeFactor }) const location = StructureElement.create(unit) const elements = unit.elements; @@ -57,7 +57,7 @@ async function createIntraUnitLinkCylinderMesh(ctx: VisualContext, unit: Unit, s flags: (edgeIndex: number) => BitFlags.create(_flags[edgeIndex]), radius: (edgeIndex: number) => { location.element = elements[a[edgeIndex]] - return sizeTheme.size(location) + return theme.size.size(location) } } diff --git a/src/mol-repr/structure/visual/nucleotide-block-mesh.ts b/src/mol-repr/structure/visual/nucleotide-block-mesh.ts index a378ee20678ef685763fb25b474a321860234cf6..e92c42fa78d777109294ad211ae44056fd300415 100644 --- a/src/mol-repr/structure/visual/nucleotide-block-mesh.ts +++ b/src/mol-repr/structure/visual/nucleotide-block-mesh.ts @@ -18,6 +18,7 @@ import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; import { addCylinder } from 'mol-geo/geometry/mesh/builder/cylinder'; import { VisualContext } from 'mol-repr'; +import { Theme } from 'mol-geo/geometry/geometry'; const p1 = Vec3.zero() const p2 = Vec3.zero() @@ -34,7 +35,7 @@ const sVec = Vec3.zero() const box = Box() // TODO define props, should be scalable -async function createNucleotideBlockMesh(ctx: VisualContext, unit: Unit, structure: Structure, props: {}, mesh?: Mesh) { +async function createNucleotideBlockMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: {}, mesh?: Mesh) { if (!Unit.isAtomic(unit)) return Mesh.createEmpty(mesh) // TODO better vertex count estimate diff --git a/src/mol-repr/structure/visual/polymer-backbone-cylinder.ts b/src/mol-repr/structure/visual/polymer-backbone-cylinder.ts index 74f2d8f59e5abfa36b389da09c11f81d39e29acd..6e3d2a7ca6965267f8bccedfa4da95500d78dd41 100644 --- a/src/mol-repr/structure/visual/polymer-backbone-cylinder.ts +++ b/src/mol-repr/structure/visual/polymer-backbone-cylinder.ts @@ -11,7 +11,6 @@ import { PolymerBackboneIterator } from './util/polymer'; import { getElementLoci, markElement, StructureElementIterator } from './util/element'; import { Vec3 } from 'mol-math/linear-algebra'; import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual'; -import { SizeTheme, SizeThemeOptions, SizeThemeName } from 'mol-theme/size'; import { OrderedSet } from 'mol-data/int'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; @@ -19,20 +18,18 @@ import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; import { CylinderProps } from 'mol-geo/primitive/cylinder'; import { addCylinder } from 'mol-geo/geometry/mesh/builder/cylinder'; import { VisualContext } from 'mol-repr'; +import { Theme } from 'mol-geo/geometry/geometry'; export const PolymerBackboneCylinderParams = { - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 1, 0, 10, 0.1), radialSegments: PD.Numeric('Radial Segments', '', 16, 3, 56, 1), } export const DefaultPolymerBackboneCylinderProps = PD.getDefaultValues(PolymerBackboneCylinderParams) export type PolymerBackboneCylinderProps = typeof DefaultPolymerBackboneCylinderProps -async function createPolymerBackboneCylinderMesh(ctx: VisualContext, unit: Unit, structure: Structure, props: PolymerBackboneCylinderProps, mesh?: Mesh) { +async function createPolymerBackboneCylinderMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PolymerBackboneCylinderProps, mesh?: Mesh) { const polymerElementCount = unit.polymerElements.length if (!polymerElementCount) return Mesh.createEmpty(mesh) - const sizeTheme = SizeTheme({ name: props.sizeTheme, value: props.sizeValue }) const { radialSegments } = props const vertexCountEstimate = radialSegments * 2 * polymerElementCount * 2 @@ -51,11 +48,11 @@ async function createPolymerBackboneCylinderMesh(ctx: VisualContext, unit: Unit, pos(centerA.element, pA) pos(centerB.element, pB) - cylinderProps.radiusTop = cylinderProps.radiusBottom = sizeTheme.size(centerA) + cylinderProps.radiusTop = cylinderProps.radiusBottom = theme.size.size(centerA) builder.setGroup(OrderedSet.indexOf(elements, centerA.element)) addCylinder(builder, pA, pB, 0.5, cylinderProps) - cylinderProps.radiusTop = cylinderProps.radiusBottom = sizeTheme.size(centerB) + cylinderProps.radiusTop = cylinderProps.radiusBottom = theme.size.size(centerB) builder.setGroup(OrderedSet.indexOf(elements, centerB.element)) addCylinder(builder, pB, pA, 0.5, cylinderProps) diff --git a/src/mol-repr/structure/visual/polymer-direction-wedge.ts b/src/mol-repr/structure/visual/polymer-direction-wedge.ts index 89b48863b08838ba2fe04f3968f1367ffc6b683a..d0f1fe4f5bc51174ea7555d4ef094d4a65931c40 100644 --- a/src/mol-repr/structure/visual/polymer-direction-wedge.ts +++ b/src/mol-repr/structure/visual/polymer-direction-wedge.ts @@ -10,12 +10,13 @@ import { PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment, import { Vec3, Mat4 } from 'mol-math/linear-algebra'; import { SecondaryStructureType, isNucleic } from 'mol-model/structure/model/types'; import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual'; -import { SizeTheme, SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; +import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { Wedge } from 'mol-geo/primitive/wedge'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; import { VisualContext } from 'mol-repr'; +import { Theme } from 'mol-geo/geometry/geometry'; const t = Mat4.identity() const sVec = Vec3.zero() @@ -36,12 +37,10 @@ export const PolymerDirectionWedgeParams = { export const DefaultPolymerDirectionWedgeProps = PD.getDefaultValues(PolymerDirectionWedgeParams) export type PolymerDirectionWedgeProps = typeof DefaultPolymerDirectionWedgeProps -async function createPolymerDirectionWedgeMesh(ctx: VisualContext, unit: Unit, structure: Structure, props: PolymerDirectionWedgeProps, mesh?: Mesh) { +async function createPolymerDirectionWedgeMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PolymerDirectionWedgeProps, mesh?: Mesh) { const polymerElementCount = unit.polymerElements.length if (!polymerElementCount) return Mesh.createEmpty(mesh) - const sizeTheme = SizeTheme({ name: props.sizeTheme, value: props.sizeValue }) - const vertexCount = polymerElementCount * 24 const builder = MeshBuilder.create(vertexCount, vertexCount / 10, mesh) const linearSegments = 1 @@ -63,7 +62,7 @@ async function createPolymerDirectionWedgeMesh(ctx: VisualContext, unit: Unit, s interpolateCurveSegment(state, v, tension, shift) if ((isSheet && !v.secStrucChange) || !isSheet) { - const size = sizeTheme.size(v.center) + const size = theme.size.size(v.center) const depth = depthFactor * size const width = widthFactor * size const height = heightFactor * size diff --git a/src/mol-repr/structure/visual/polymer-gap-cylinder.ts b/src/mol-repr/structure/visual/polymer-gap-cylinder.ts index 56a83b2c1391eee19dce06333e1ee11bd094d4a3..60585ab0d8965770c9662f1eb28825c750b64bf9 100644 --- a/src/mol-repr/structure/visual/polymer-gap-cylinder.ts +++ b/src/mol-repr/structure/visual/polymer-gap-cylinder.ts @@ -10,7 +10,7 @@ import { VisualUpdateState } from '../../util'; import { PolymerGapIterator, PolymerGapLocationIterator, markPolymerGapElement, getPolymerGapElementLoci } from './util/polymer'; import { Vec3 } from 'mol-math/linear-algebra'; import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual'; -import { SizeTheme, SizeThemeOptions, SizeThemeName } from 'mol-theme/size'; +import { SizeThemeOptions, SizeThemeName } from 'mol-theme/size'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { LinkCylinderParams } from './util/link'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; @@ -19,23 +19,20 @@ import { CylinderProps } from 'mol-geo/primitive/cylinder'; import { addSphere } from 'mol-geo/geometry/mesh/builder/sphere'; import { addFixedCountDashedCylinder } from 'mol-geo/geometry/mesh/builder/cylinder'; import { VisualContext } from 'mol-repr'; +import { Theme } from 'mol-geo/geometry/geometry'; const segmentCount = 10 export const PolymerGapCylinderParams = { - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 1, 0, 10, 0.1), - sizeFactor: PD.Numeric('Size Factor', '', 0.3, 0, 10, 0.1), radialSegments: PD.Numeric('Radial Segments', '', 16, 3, 56, 1), } export const DefaultPolymerGapCylinderProps = PD.getDefaultValues(PolymerGapCylinderParams) export type PolymerGapCylinderProps = typeof DefaultPolymerGapCylinderProps -async function createPolymerGapCylinderMesh(ctx: VisualContext, unit: Unit, structure: Structure, props: PolymerGapCylinderProps, mesh?: Mesh) { +async function createPolymerGapCylinderMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PolymerGapCylinderProps, mesh?: Mesh) { const polymerGapCount = unit.gapElements.length if (!polymerGapCount) return Mesh.createEmpty(mesh) - const sizeTheme = SizeTheme({ name: props.sizeTheme, value: props.sizeValue, factor: props.sizeValue }) const { radialSegments } = props const vertexCountEstimate = segmentCount * radialSegments * 2 * polymerGapCount * 2 @@ -60,11 +57,11 @@ async function createPolymerGapCylinderMesh(ctx: VisualContext, unit: Unit, stru pos(centerA.element, pA) pos(centerB.element, pB) - cylinderProps.radiusTop = cylinderProps.radiusBottom = sizeTheme.size(centerA) + cylinderProps.radiusTop = cylinderProps.radiusBottom = theme.size.size(centerA) builder.setGroup(i) addFixedCountDashedCylinder(builder, pA, pB, 0.5, segmentCount, cylinderProps) - cylinderProps.radiusTop = cylinderProps.radiusBottom = sizeTheme.size(centerB) + cylinderProps.radiusTop = cylinderProps.radiusBottom = theme.size.size(centerB) builder.setGroup(i + 1) addFixedCountDashedCylinder(builder, pB, pA, 0.5, segmentCount, cylinderProps) } diff --git a/src/mol-repr/structure/visual/polymer-trace-mesh.ts b/src/mol-repr/structure/visual/polymer-trace-mesh.ts index 934b81911aecda1655ff4b5931bc603ddd9b397e..8f75d29ed49f88e8e72ec399f79b6f6801835a9d 100644 --- a/src/mol-repr/structure/visual/polymer-trace-mesh.ts +++ b/src/mol-repr/structure/visual/polymer-trace-mesh.ts @@ -10,18 +10,15 @@ import { VisualUpdateState } from '../../util'; import { PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment, PolymerLocationIterator, getPolymerElementLoci, markPolymerElement } from './util/polymer'; import { SecondaryStructureType, isNucleic } from 'mol-model/structure/model/types'; import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual'; -import { SizeTheme, SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; import { addSheet } from 'mol-geo/geometry/mesh/builder/sheet'; import { addTube } from 'mol-geo/geometry/mesh/builder/tube'; import { VisualContext } from 'mol-repr'; +import { Theme } from 'mol-geo/geometry/geometry'; export const PolymerTraceMeshParams = { - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1), - sizeFactor: PD.Numeric('Size Factor', '', 0.3, 0, 10, 0.1), linearSegments: PD.Numeric('Linear Segments', '', 8, 1, 48, 1), radialSegments: PD.Numeric('Radial Segments', '', 16, 3, 56, 1), aspectRatio: PD.Numeric('Aspect Ratio', '', 5, 0.1, 5, 0.1), @@ -32,11 +29,10 @@ export type PolymerTraceMeshProps = typeof DefaultPolymerTraceMeshProps // TODO handle polymer ends properly -async function createPolymerTraceMesh(ctx: VisualContext, unit: Unit, structure: Structure, props: PolymerTraceMeshProps, mesh?: Mesh) { +async function createPolymerTraceMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PolymerTraceMeshProps, mesh?: Mesh) { const polymerElementCount = unit.polymerElements.length if (!polymerElementCount) return Mesh.createEmpty(mesh) - const sizeTheme = SizeTheme({ name: props.sizeTheme, value: props.sizeValue, factor: props.sizeFactor }) const { linearSegments, radialSegments, aspectRatio, arrowFactor } = props const vertexCount = linearSegments * radialSegments * polymerElementCount + (radialSegments + 1) * polymerElementCount * 2 @@ -60,7 +56,7 @@ async function createPolymerTraceMesh(ctx: VisualContext, unit: Unit, structure: interpolateCurveSegment(state, v, tension, shift) - let width = sizeTheme.size(v.center) + let width = theme.size.size(v.center) if (isCoarse) width *= aspectRatio / 2 if (isSheet) { diff --git a/src/mol-repr/structure/visual/util/common.ts b/src/mol-repr/structure/visual/util/common.ts index a0cff0c67bd20c61ab0626bfa00bc8dbdd48f064..25598d6e34efc0d16031ab5984b1b25f4548f2a8 100644 --- a/src/mol-repr/structure/visual/util/common.ts +++ b/src/mol-repr/structure/visual/util/common.ts @@ -11,7 +11,7 @@ import { Mat4 } from 'mol-math/linear-algebra'; import { TransformData, createTransform, createIdentityTransform } from 'mol-geo/geometry/transform-data'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { LocationIterator } from 'mol-geo/util/location-iterator'; -import { createRenderableState } from 'mol-geo/geometry/geometry'; +import { createRenderableState, Theme } from 'mol-geo/geometry/geometry'; import { Points } from 'mol-geo/geometry/points/points'; import { Lines } from 'mol-geo/geometry/lines/lines'; import { DirectVolume } from 'mol-geo/geometry/direct-volume/direct-volume'; @@ -49,16 +49,16 @@ export function includesUnitKind(unitKinds: UnitKind[], unit: Unit) { type StructureMeshProps = Mesh.Props & StructureProps -export async function createComplexMeshRenderObject(ctx: VisualContext, structure: Structure, mesh: Mesh, locationIt: LocationIterator, props: StructureMeshProps) { +export async function createComplexMeshRenderObject(ctx: VisualContext, structure: Structure, mesh: Mesh, locationIt: LocationIterator, theme: Theme, props: StructureMeshProps) { const transform = createIdentityTransform() - const values = await Mesh.createValues(ctx.runtime, mesh, transform, locationIt, props) + const values = await Mesh.createValues(ctx.runtime, mesh, transform, locationIt, theme, props) const state = createRenderableState(props) return createMeshRenderObject(values, state) } -export async function createUnitsMeshRenderObject(ctx: VisualContext, group: Unit.SymmetryGroup, mesh: Mesh, locationIt: LocationIterator, props: StructureMeshProps) { +export async function createUnitsMeshRenderObject(ctx: VisualContext, group: Unit.SymmetryGroup, mesh: Mesh, locationIt: LocationIterator, theme: Theme, props: StructureMeshProps) { const transform = createUnitsTransform(group) - const values = await Mesh.createValues(ctx.runtime, mesh, transform, locationIt, props) + const values = await Mesh.createValues(ctx.runtime, mesh, transform, locationIt, theme, props) const state = createRenderableState(props) return createMeshRenderObject(values, state) } @@ -67,9 +67,9 @@ export async function createUnitsMeshRenderObject(ctx: VisualContext, group: Uni type StructurePointsProps = Points.Props & StructureProps -export async function createUnitsPointsRenderObject(ctx: VisualContext, group: Unit.SymmetryGroup, points: Points, locationIt: LocationIterator, props: StructurePointsProps) { +export async function createUnitsPointsRenderObject(ctx: VisualContext, group: Unit.SymmetryGroup, points: Points, locationIt: LocationIterator, theme: Theme, props: StructurePointsProps) { const transform = createUnitsTransform(group) - const values = await Points.createValues(ctx.runtime, points, transform, locationIt, props) + const values = await Points.createValues(ctx.runtime, points, transform, locationIt, theme, props) const state = createRenderableState(props) return createPointsRenderObject(values, state) } @@ -78,9 +78,9 @@ export async function createUnitsPointsRenderObject(ctx: VisualContext, group: U type StructureLinesProps = Lines.Props & StructureProps -export async function createUnitsLinesRenderObject(ctx: VisualContext, group: Unit.SymmetryGroup, lines: Lines, locationIt: LocationIterator, props: StructureLinesProps) { +export async function createUnitsLinesRenderObject(ctx: VisualContext, group: Unit.SymmetryGroup, lines: Lines, locationIt: LocationIterator, theme: Theme, props: StructureLinesProps) { const transform = createUnitsTransform(group) - const values = await Lines.createValues(ctx.runtime, lines, transform, locationIt, props) + const values = await Lines.createValues(ctx.runtime, lines, transform, locationIt, theme, props) const state = createRenderableState(props) return createLinesRenderObject(values, state) } @@ -89,9 +89,9 @@ export async function createUnitsLinesRenderObject(ctx: VisualContext, group: Un type StructureDirectVolumeProps = DirectVolume.Props & StructureProps -export async function createUnitsDirectVolumeRenderObject(ctx: VisualContext, group: Unit.SymmetryGroup, directVolume: DirectVolume, locationIt: LocationIterator, props: StructureDirectVolumeProps) { +export async function createUnitsDirectVolumeRenderObject(ctx: VisualContext, group: Unit.SymmetryGroup, directVolume: DirectVolume, locationIt: LocationIterator, theme: Theme, props: StructureDirectVolumeProps) { const transform = createUnitsTransform(group) - const values = await DirectVolume.createValues(ctx.runtime, directVolume, transform, locationIt, props) + const values = await DirectVolume.createValues(ctx.runtime, directVolume, transform, locationIt, theme, props) const state = createRenderableState(props) return createDirectVolumeRenderObject(values, state) } \ No newline at end of file diff --git a/src/mol-repr/structure/visual/util/element.ts b/src/mol-repr/structure/visual/util/element.ts index 909bce22aa260a8a8491c31d1cc015d4c7f90dac..e1ccb69774b2497ffd08b7a936f497d67c1ca5e8 100644 --- a/src/mol-repr/structure/visual/util/element.ts +++ b/src/mol-repr/structure/visual/util/element.ts @@ -8,7 +8,6 @@ import { Vec3 } from 'mol-math/linear-algebra'; import { Unit, StructureElement, Structure } from 'mol-model/structure'; import { Loci, EmptyLoci } from 'mol-model/loci'; import { Interval, OrderedSet } from 'mol-data/int'; -import { SizeTheme, SizeThemeName } from 'mol-theme/size'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { sphereVertexCount } from 'mol-geo/primitive/sphere'; import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; @@ -16,18 +15,16 @@ import { addSphere } from 'mol-geo/geometry/mesh/builder/sphere'; import { PickingId } from 'mol-geo/geometry/picking'; import { LocationIterator } from 'mol-geo/util/location-iterator'; import { VisualContext } from 'mol-repr'; +import { Theme } from 'mol-geo/geometry/geometry'; export interface ElementSphereMeshProps { - sizeTheme: SizeThemeName, - sizeValue: number, detail: number, } -export async function createElementSphereMesh(ctx: VisualContext, unit: Unit, structure: Structure, props: ElementSphereMeshProps, mesh?: Mesh) { +export async function createElementSphereMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: ElementSphereMeshProps, mesh?: Mesh) { const { detail } = props const { elements } = unit; - const sizeTheme = SizeTheme({ name: props.sizeTheme, value: props.sizeValue }) const elementCount = elements.length; const vertexCount = elementCount * sphereVertexCount(detail) const meshBuilder = MeshBuilder.create(vertexCount, vertexCount / 2, mesh) @@ -42,7 +39,7 @@ export async function createElementSphereMesh(ctx: VisualContext, unit: Unit, st pos(elements[i], v) meshBuilder.setGroup(i) - addSphere(meshBuilder, v, sizeTheme.size(l), detail) + addSphere(meshBuilder, v, theme.size.size(l), detail) if (i % 10000 === 0 && ctx.runtime.shouldUpdate) { await ctx.runtime.update({ message: 'Sphere mesh', current: i, max: elementCount }); diff --git a/src/mol-repr/structure/visual/util/link.ts b/src/mol-repr/structure/visual/util/link.ts index 41932fa0fd3538a7094c1d4e3ae4b5c10fd0a411..2ea26bff5c8311b488d343fbee6d9e18795eaf6a 100644 --- a/src/mol-repr/structure/visual/util/link.ts +++ b/src/mol-repr/structure/visual/util/link.ts @@ -6,7 +6,6 @@ import { Vec3 } from 'mol-math/linear-algebra'; import { LinkType } from 'mol-model/structure/model/types'; -import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; import { Unit, StructureElement, Structure, Link } from 'mol-model/structure'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; @@ -17,9 +16,6 @@ import { LocationIterator } from 'mol-geo/util/location-iterator'; import { VisualContext } from 'mol-repr'; export const LinkCylinderParams = { - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1), - sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1), linkScale: PD.Range('Link Scale', '', 0.4, 0, 1, 0.1), linkSpacing: PD.Range('Link Spacing', '', 1, 0, 2, 0.01), linkRadius: PD.Range('Link Radius', '', 0.25, 0, 10, 0.05), diff --git a/src/mol-repr/util.ts b/src/mol-repr/util.ts index 0b71cd247d96592ae3dc676a30a4fd54b88cb27b..4db8e0cee7c100f8650074fb216192c9bec3379b 100644 --- a/src/mol-repr/util.ts +++ b/src/mol-repr/util.ts @@ -61,16 +61,16 @@ export interface QualityProps { resolution: number } -export function getQualityProps(props: Partial<QualityProps>, structure?: Structure) { +export function getQualityProps(props: Partial<QualityProps>, data?: any) { let quality = defaults(props.quality, 'auto' as VisualQuality) let detail = defaults(props.detail, 1) let radialSegments = defaults(props.radialSegments, 12) let linearSegments = defaults(props.linearSegments, 8) let resolution = defaults(props.resolution, 2) - if (quality === 'auto' && structure) { - let score = structure.elementCount - if (structure.isCoarse) score *= 10 + if (quality === 'auto' && data instanceof Structure) { + let score = data.elementCount + if (data.isCoarse) score *= 10 if (score > 500_000) { quality = 'lowest' } else if (score > 300_000) { diff --git a/src/mol-repr/volume/direct-volume.ts b/src/mol-repr/volume/direct-volume.ts index adc324e4e6af5257b878f9d85a69695e77aa0cf1..50e4cc7a210b0e6bdc842251b5b8431f68c6374f 100644 --- a/src/mol-repr/volume/direct-volume.ts +++ b/src/mol-repr/volume/direct-volume.ts @@ -17,7 +17,7 @@ import { createTexture } from 'mol-gl/webgl/texture'; import { LocationIterator } from 'mol-geo/util/location-iterator'; import { createIdentityTransform } from 'mol-geo/geometry/transform-data'; import { DirectVolume } from 'mol-geo/geometry/direct-volume/direct-volume'; -import { Geometry, createRenderableState } from 'mol-geo/geometry/geometry'; +import { Geometry, createRenderableState, Theme } from 'mol-geo/geometry/geometry'; import { PickingId } from 'mol-geo/geometry/picking'; import { MarkerAction } from 'mol-geo/geometry/marker-data'; import { VisualUpdateState } from 'mol-repr/util'; @@ -198,9 +198,9 @@ export function DirectVolumeVisual(): VolumeVisual<DirectVolumeProps> { mark: () => false, setUpdateState: (state: VisualUpdateState, newProps: DirectVolumeProps, currentProps: DirectVolumeProps) => { }, - createRenderObject: async (ctx: VisualContext, geometry: DirectVolume, locationIt: LocationIterator, props: DirectVolumeProps) => { + createRenderObject: async (ctx: VisualContext, geometry: DirectVolume, locationIt: LocationIterator, theme: Theme, props: DirectVolumeProps) => { const transform = createIdentityTransform() - const values = await DirectVolume.createValues(ctx.runtime, geometry, transform, locationIt, props) + const values = await DirectVolume.createValues(ctx.runtime, geometry, transform, locationIt, theme, props) const state = createRenderableState(props) return createDirectVolumeRenderObject(values, state) }, diff --git a/src/mol-repr/volume/index.ts b/src/mol-repr/volume/index.ts index a4b09a7d6eeaa8d5d03bd7280a86fe4f1c586fec..729f53cff94fda9ccffa9a722ea05f9143ec643f 100644 --- a/src/mol-repr/volume/index.ts +++ b/src/mol-repr/volume/index.ts @@ -8,8 +8,8 @@ import { Task } from 'mol-task' import { RepresentationProps, Representation, Visual, RepresentationContext, VisualContext } from '..'; import { VolumeData, VolumeIsoValue } from 'mol-model/volume'; import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci'; +import { Geometry, updateRenderableState, Theme, createTheme } from 'mol-geo/geometry/geometry'; import { ParamDefinition as PD } from 'mol-util/param-definition'; -import { Geometry, updateRenderableState } from 'mol-geo/geometry/geometry'; import { PickingId } from 'mol-geo/geometry/picking'; import { MarkerAction, applyMarkerAction } from 'mol-geo/geometry/marker-data'; import { DirectVolumeRenderObject, PointsRenderObject, LinesRenderObject, MeshRenderObject } from 'mol-gl/render-object'; @@ -33,7 +33,7 @@ interface VolumeVisualBuilder<P extends VolumeProps, G extends Geometry> { } interface VolumeVisualGeometryBuilder<P extends VolumeProps, G extends Geometry> extends VolumeVisualBuilder<P, G> { - createRenderObject(ctx: VisualContext, geometry: G, locationIt: LocationIterator, currentProps: P): Promise<VolumeRenderObject> + createRenderObject(ctx: VisualContext, geometry: G, locationIt: LocationIterator, theme: Theme, currentProps: P): Promise<VolumeRenderObject> updateValues(values: RenderableValues, newProps: P): void } @@ -48,25 +48,25 @@ export function VolumeVisual<P extends VolumeProps>(builder: VolumeVisualGeometr let geometry: Geometry let locationIt: LocationIterator - async function create(ctx: VisualContext, volume: VolumeData, props: Partial<VolumeProps> = {}) { + async function create(ctx: VisualContext, volume: VolumeData, theme: Theme, props: Partial<VolumeProps> = {}) { currentProps = Object.assign({}, defaultProps, props) if (props.isoValueRelative) { currentProps.isoValueAbsolute = VolumeIsoValue.calcAbsolute(currentVolume.dataStats, props.isoValueRelative) - console.log('create props.isoValueRelative', props.isoValueRelative, currentProps.isoValueAbsolute, currentVolume.dataStats) + // console.log('create props.isoValueRelative', props.isoValueRelative, currentProps.isoValueAbsolute, currentVolume.dataStats) } geometry = await createGeometry(ctx, volume, currentProps, geometry) locationIt = LocationIterator(1, 1, () => NullLocation) - renderObject = await createRenderObject(ctx, geometry, locationIt, currentProps) + renderObject = await createRenderObject(ctx, geometry, locationIt, theme, currentProps) } - async function update(ctx: VisualContext, props: Partial<VolumeProps> = {}) { + async function update(ctx: VisualContext, theme: Theme, props: Partial<VolumeProps> = {}) { if (!renderObject) return const newProps = Object.assign({}, currentProps, props) if (props.isoValueRelative) { newProps.isoValueAbsolute = VolumeIsoValue.calcAbsolute(currentVolume.dataStats, props.isoValueRelative) - console.log('update props.isoValueRelative', props.isoValueRelative, newProps.isoValueAbsolute, currentVolume.dataStats) + // console.log('update props.isoValueRelative', props.isoValueRelative, newProps.isoValueAbsolute, currentVolume.dataStats) } VisualUpdateState.reset(updateState) @@ -85,17 +85,17 @@ export function VolumeVisual<P extends VolumeProps>(builder: VolumeVisualGeometr return { get renderObject () { return renderObject }, - async createOrUpdate(ctx: VisualContext, props: Partial<VolumeProps> = {}, volume?: VolumeData) { + async createOrUpdate(ctx: VisualContext, theme: Theme, props: Partial<VolumeProps> = {}, volume?: VolumeData) { if (!volume && !currentVolume) { throw new Error('missing volume') } else if (volume && (!currentVolume || !renderObject)) { currentVolume = volume - await create(ctx, volume, props) + await create(ctx, volume, theme, props) } else if (volume && volume !== currentVolume) { currentVolume = volume - await create(ctx, volume, props) + await create(ctx, volume, theme, props) } else { - await update(ctx, props) + await update(ctx, theme, props) } currentProps = Object.assign({}, defaultProps, props) @@ -145,10 +145,13 @@ export type VolumeProps = typeof DefaultVolumeProps export function VolumeRepresentation<P extends VolumeProps>(visualCtor: (volumeData: VolumeData) => VolumeVisual<P>): VolumeRepresentation<P> { let visual: VolumeVisual<any> let _props: P + let _theme: Theme let busy = false function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, volumeData?: VolumeData) { _props = Object.assign({}, DefaultVolumeProps, _props, props) + _theme = createTheme(_props) + return Task.create('VolumeRepresentation.create', async runtime => { // TODO queue it somehow if (busy) return @@ -158,11 +161,11 @@ export function VolumeRepresentation<P extends VolumeProps>(visualCtor: (volumeD } else if (volumeData && !visual) { busy = true visual = visualCtor(volumeData) - await visual.createOrUpdate({ ...ctx, runtime } , props, volumeData) + await visual.createOrUpdate({ ...ctx, runtime }, _theme, _props, volumeData) busy = false } else { busy = true - await visual.createOrUpdate({ ...ctx, runtime }, props, volumeData) + await visual.createOrUpdate({ ...ctx, runtime }, _theme, _props, volumeData) busy = false } }); diff --git a/src/mol-repr/volume/isosurface-mesh.ts b/src/mol-repr/volume/isosurface-mesh.ts index c09f89797c4d39f79675a526419facf04f5ee39b..13eb6f3744de657b50995a8c4ab0a736f23d8789 100644 --- a/src/mol-repr/volume/isosurface-mesh.ts +++ b/src/mol-repr/volume/isosurface-mesh.ts @@ -14,7 +14,7 @@ import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { computeMarchingCubesMesh } from 'mol-geo/util/marching-cubes/algorithm'; import { LocationIterator } from 'mol-geo/util/location-iterator'; import { createIdentityTransform } from 'mol-geo/geometry/transform-data'; -import { createRenderableState } from 'mol-geo/geometry/geometry'; +import { createRenderableState, Theme } from 'mol-geo/geometry/geometry'; import { PickingId } from 'mol-geo/geometry/picking'; import { MarkerAction } from 'mol-geo/geometry/marker-data'; import { VisualUpdateState } from 'mol-repr/util'; @@ -57,9 +57,9 @@ export function IsosurfaceVisual(): VolumeVisual<IsosurfaceProps> { setUpdateState: (state: VisualUpdateState, newProps: IsosurfaceProps, currentProps: IsosurfaceProps) => { if (newProps.isoValueAbsolute !== currentProps.isoValueAbsolute) state.createGeometry = true }, - createRenderObject: async (ctx: VisualContext, geometry: Mesh, locationIt: LocationIterator, props: IsosurfaceProps) => { + createRenderObject: async (ctx: VisualContext, geometry: Mesh, locationIt: LocationIterator, theme: Theme, props: IsosurfaceProps) => { const transform = createIdentityTransform() - const values = await Mesh.createValues(ctx.runtime, geometry, transform, locationIt, props) + const values = await Mesh.createValues(ctx.runtime, geometry, transform, locationIt, theme, props) const state = createRenderableState(props) return createMeshRenderObject(values, state) }, diff --git a/src/mol-theme/color/chain-id.ts b/src/mol-theme/color/chain-id.ts index 0fd9e3955a12238e72496d5e527a8a7e71741944..c91825e4729d16b1777eceb17796f75906109baf 100644 --- a/src/mol-theme/color/chain-id.ts +++ b/src/mol-theme/color/chain-id.ts @@ -25,7 +25,7 @@ function getAsymId(unit: Unit): StructureElement.Property<string> { export function ChainIdColorTheme(props: ColorThemeProps): ColorTheme { let color: LocationColor - let scale: ColorScale | undefined = undefined + const scale = ColorScale.create({ list: props.list, minLabel: 'Start', maxLabel: 'End' }) // const table: [string, Color][] = [] if (props.structure) { @@ -41,7 +41,7 @@ export function ChainIdColorTheme(props: ColorThemeProps): ColorTheme { } }) } - scale = ColorScale.create({ domain: [ 0, asymIdSerialMap.size - 1 ] }) + scale.setDomain(0, asymIdSerialMap.size - 1) const scaleColor = scale.color // asymIdSerialMap.forEach((v, k) => table.push([k, scaleColor(v)])) @@ -63,7 +63,7 @@ export function ChainIdColorTheme(props: ColorThemeProps): ColorTheme { } return { - features: {}, + features: { structure: true, list: true }, granularity: 'group', color, description: Description, diff --git a/src/mol-theme/color/cross-link.ts b/src/mol-theme/color/cross-link.ts index bb3cf176c4f5a5c8fdbc330b63e7c69e5436c089..d24b79e4a92b4e45f7f887df5e333066f0be69c0 100644 --- a/src/mol-theme/color/cross-link.ts +++ b/src/mol-theme/color/cross-link.ts @@ -49,7 +49,7 @@ export function CrossLinkColorTheme(props: ColorThemeProps): ColorTheme { } return { - features: { list: true, domain: true }, + features: { list: true, domain: true, structure: true }, granularity: 'group', color, description: Description, diff --git a/src/mol-theme/color/element-index.ts b/src/mol-theme/color/element-index.ts index ecce0a1c1bc0804043f2c9ee4c5f8aaabbc69882..2ba30ce687307d87d5caa9fb34a9db98c71c4e91 100644 --- a/src/mol-theme/color/element-index.ts +++ b/src/mol-theme/color/element-index.ts @@ -15,7 +15,7 @@ const Description = 'Gives every element (atom or coarse sphere/gaussian) a uniq export function ElementIndexColorTheme(props: ColorThemeProps): ColorTheme { let color: LocationColor - let scale: ColorScale | undefined = undefined + let scale = ColorScale.create({ list: props.list, minLabel: 'Start', maxLabel: 'End' }) if (props.structure) { const { units } = props.structure @@ -29,7 +29,7 @@ export function ElementIndexColorTheme(props: ColorThemeProps): ColorTheme { elementCount += units[i].elements.length unitIdIndex.set(units[i].id, i) } - scale = ColorScale.create({ domain: [ 0, elementCount - 1 ], list: props.list }) + scale.setDomain(0, elementCount - 1) const scaleColor = scale.color color = (location: Location): Color => { @@ -48,7 +48,7 @@ export function ElementIndexColorTheme(props: ColorThemeProps): ColorTheme { } return { - features: { list: true }, + features: { structure: true, list: true }, granularity: 'groupInstance', color, description: Description, diff --git a/src/mol-theme/color/polymer-index.ts b/src/mol-theme/color/polymer-index.ts index b32fa80cbaa1649bbdf2b0aed8d2ace1f6f9b3e8..b17a57dfe8a526c52dc1de93d0e5cee1ba558c0f 100644 --- a/src/mol-theme/color/polymer-index.ts +++ b/src/mol-theme/color/polymer-index.ts @@ -14,7 +14,7 @@ const Description = 'Gives every polymer a unique color based on the position (i export function PolymerIndexColorTheme(props: ColorThemeProps): ColorTheme { let color: LocationColor - let scale: ColorScale | undefined = undefined + const scale = ColorScale.create({ list: props.list, minLabel: 'Start', maxLabel: 'End' }) if (props.structure) { const { units } = props.structure @@ -22,7 +22,7 @@ export function PolymerIndexColorTheme(props: ColorThemeProps): ColorTheme { for (let i = 0, il = units.length; i <il; ++i) { if (units[i].polymerElements.length > 0) ++polymerCount } - scale = ColorScale.create({ list: props.list, domain: [ 0, polymerCount - 1 ] }) + scale.setDomain(0, polymerCount - 1) const unitIdColor = new Map<number, Color>() for (let i = 0, j = 0, il = units.length; i <il; ++i) { if (units[i].polymerElements.length > 0) { diff --git a/src/mol-theme/color/unit-index.ts b/src/mol-theme/color/unit-index.ts index f41b29199a01f064b84b4c3155fd64b06da9c4cd..a17dc82b6e40a5c7ac2782a970d248b682e0fd7b 100644 --- a/src/mol-theme/color/unit-index.ts +++ b/src/mol-theme/color/unit-index.ts @@ -14,11 +14,11 @@ const Description = 'Gives every unit (single chain or collection of single elem export function UnitIndexColorTheme(props: ColorThemeProps): ColorTheme { let color: LocationColor - let scale: ColorScale | undefined = undefined + const scale = ColorScale.create({ list: props.list, minLabel: 'Start', maxLabel: 'End' }) if (props.structure) { const { units } = props.structure - scale = ColorScale.create({ domain: [ 0, units.length - 1 ] }) + scale.setDomain(0, units.length - 1) const unitIdColor = new Map<number, Color>() for (let i = 0, il = units.length; i <il; ++i) { unitIdColor.set(units[i].id, scale.color(i)) @@ -37,7 +37,7 @@ export function UnitIndexColorTheme(props: ColorThemeProps): ColorTheme { } return { - features: {}, + features: { structure: true, list: true }, granularity: 'instance', color, description: Description,