Pārlūkot izejas kodu

improved measurement representation labels

Alexander Rose 5 gadi atpakaļ
vecāks
revīzija
142c46c127

+ 1 - 1
src/mol-plugin/state/transforms/helpers.ts

@@ -55,5 +55,5 @@ export function getLabelDataFromStructureSelections(s: ReadonlyArray<PluginState
 
 export function getOrientationDataFromStructureSelections(s: ReadonlyArray<PluginStateObject.Molecule.Structure.SelectionEntry>): OrientationData {
     const loci = s[0].loci
-    return { loci }
+    return { locis: [loci] }
 }

+ 19 - 10
src/mol-repr/shape/loci/angle.ts

@@ -142,12 +142,16 @@ function getCircle(state: AngleState, segmentLength?: number) {
 
 const tmpState = getAngleState()
 
-function angleLabel(triple: Loci.Bundle<3>, arcScale: number) {
-    setAngleState(triple, tmpState, arcScale)
+function angleLabel(triple: Loci.Bundle<3>) {
+    setAngleState(triple, tmpState, 1)
     const angle = radToDeg(tmpState.angle).toFixed(2)
     return `Angle ${angle}\u00B0`
 }
 
+function getAngleName(data: AngleData) {
+    return data.triples.length === 1 ? angleLabel(data.triples[0]) : `${data.triples.length} Angles`
+}
+
 //
 
 function buildVectorsLines(data: AngleData, props: AngleProps, lines?: Lines): Lines {
@@ -162,10 +166,11 @@ function buildVectorsLines(data: AngleData, props: AngleProps, lines?: Lines): L
 
 function getVectorsShape(ctx: RuntimeContext, data: AngleData, props: AngleProps, shape?: Shape<Lines>) {
     const lines = buildVectorsLines(data, props, shape && shape.geometry);
+    const name = getAngleName(data)
     const getLabel = function (groupId: number ) {
-        return angleLabel(data.triples[groupId], props.arcScale)
+        return angleLabel(data.triples[groupId])
     }
-    return Shape.create('Angle Vectors', data, lines, () => props.color, () => props.linesSize, getLabel)
+    return Shape.create(name, data, lines, () => props.color, () => props.linesSize, getLabel)
 }
 
 //
@@ -194,10 +199,11 @@ function buildArcLines(data: AngleData, props: AngleProps, lines?: Lines): Lines
 
 function getArcShape(ctx: RuntimeContext, data: AngleData, props: AngleProps, shape?: Shape<Lines>) {
     const lines = buildArcLines(data, props, shape && shape.geometry);
+    const name = getAngleName(data)
     const getLabel = function (groupId: number ) {
-        return angleLabel(data.triples[groupId], props.arcScale)
+        return angleLabel(data.triples[groupId])
     }
-    return Shape.create('Angle Arc', data, lines, () => props.color, () => props.linesSize, getLabel)
+    return Shape.create(name, data, lines, () => props.color, () => props.linesSize, getLabel)
 }
 
 //
@@ -207,6 +213,7 @@ function buildSectorMesh(data: AngleData, props: AngleProps, mesh?: Mesh): Mesh
     for (let i = 0, il = data.triples.length; i < il; ++i) {
         setAngleState(data.triples[i], tmpState, props.arcScale)
         const circle = getCircle(tmpState)
+        state.currentGroup = i
         MeshBuilder.addPrimitive(state, Mat4.id, circle)
         MeshBuilder.addPrimitiveFlipped(state, Mat4.id, circle)
     }
@@ -215,10 +222,11 @@ function buildSectorMesh(data: AngleData, props: AngleProps, mesh?: Mesh): Mesh
 
 function getSectorShape(ctx: RuntimeContext, data: AngleData, props: AngleProps, shape?: Shape<Mesh>) {
     const mesh = buildSectorMesh(data, props, shape && shape.geometry);
+    const name = getAngleName(data)
     const getLabel = function (groupId: number ) {
-        return angleLabel(data.triples[groupId], props.arcScale)
+        return angleLabel(data.triples[groupId])
     }
-    return Shape.create('Angle Sector', data, mesh, () => props.color, () => 1, getLabel)
+    return Shape.create(name, data, mesh, () => props.color, () => 1, getLabel)
 }
 
 //
@@ -241,10 +249,11 @@ function buildText(data: AngleData, props: AngleProps, text?: Text): Text {
 
 function getTextShape(ctx: RuntimeContext, data: AngleData, props: AngleProps, shape?: Shape<Text>) {
     const text = buildText(data, props, shape && shape.geometry);
+    const name = getAngleName(data)
     const getLabel = function (groupId: number ) {
-        return angleLabel(data.triples[groupId], props.arcScale)
+        return angleLabel(data.triples[groupId])
     }
-    return Shape.create('Angle Text', data, text, () => props.textColor, () => props.textSize, getLabel)
+    return Shape.create(name, data, text, () => props.textColor, () => props.textSize, getLabel)
 }
 
 //

+ 22 - 12
src/mol-repr/shape/loci/dihedral.ts

@@ -184,12 +184,16 @@ function getCircle(state: DihedralState, segmentLength?: number) {
 }
 
 const tmpState = getDihedralState()
-function dihedralLabel(quad: Loci.Bundle<4>, arcScale: number) {
-    setDihedralState(quad, tmpState, arcScale)
+function dihedralLabel(quad: Loci.Bundle<4>) {
+    setDihedralState(quad, tmpState, 1)
     const angle = radToDeg(tmpState.angle).toFixed(2)
     return `Dihedral ${angle}\u00B0`
 }
 
+function getDihedralName(data: DihedralData) {
+    return data.quads.length === 1 ? dihedralLabel(data.quads[0]) : `${data.quads.length} Dihedrals`
+}
+
 //
 
 function buildVectorsLines(data: DihedralData, props: DihedralProps, lines?: Lines): Lines {
@@ -204,10 +208,11 @@ function buildVectorsLines(data: DihedralData, props: DihedralProps, lines?: Lin
 
 function getVectorsShape(ctx: RuntimeContext, data: DihedralData, props: DihedralProps, shape?: Shape<Lines>) {
     const lines = buildVectorsLines(data, props, shape && shape.geometry);
+    const name = getDihedralName(data)
     const getLabel = function (groupId: number ) {
-        return dihedralLabel(data.quads[groupId], props.arcScale)
+        return dihedralLabel(data.quads[groupId])
     }
-    return Shape.create('Dihedral Vectors', data, lines, () => props.color, () => props.linesSize, getLabel)
+    return Shape.create(name, data, lines, () => props.color, () => props.linesSize, getLabel)
 }
 
 //
@@ -224,10 +229,11 @@ function buildExtendersLines(data: DihedralData, props: DihedralProps, lines?: L
 
 function getExtendersShape(ctx: RuntimeContext, data: DihedralData, props: DihedralProps, shape?: Shape<Lines>) {
     const lines = buildExtendersLines(data, props, shape && shape.geometry);
+    const name = getDihedralName(data)
     const getLabel = function (groupId: number ) {
-        return dihedralLabel(data.quads[groupId], props.arcScale)
+        return dihedralLabel(data.quads[groupId])
     }
-    return Shape.create('Dihedral Extenders', data, lines, () => props.color, () => props.linesSize, getLabel)
+    return Shape.create(name, data, lines, () => props.color, () => props.linesSize, getLabel)
 }
 
 //
@@ -256,10 +262,11 @@ function buildArcLines(data: DihedralData, props: DihedralProps, lines?: Lines):
 
 function getArcShape(ctx: RuntimeContext, data: DihedralData, props: DihedralProps, shape?: Shape<Lines>) {
     const lines = buildArcLines(data, props, shape && shape.geometry);
+    const name = getDihedralName(data)
     const getLabel = function (groupId: number ) {
-        return dihedralLabel(data.quads[groupId], props.arcScale)
+        return dihedralLabel(data.quads[groupId])
     }
-    return Shape.create('Dihedral Arc', data, lines, () => props.color, () => props.linesSize, getLabel)
+    return Shape.create(name, data, lines, () => props.color, () => props.linesSize, getLabel)
 }
 
 //
@@ -269,6 +276,7 @@ function buildSectorMesh(data: DihedralData, props: DihedralProps, mesh?: Mesh):
     for (let i = 0, il = data.quads.length; i < il; ++i) {
         setDihedralState(data.quads[i], tmpState, props.arcScale)
         const circle = getCircle(tmpState)
+        state.currentGroup = i
         MeshBuilder.addPrimitive(state, Mat4.id, circle)
         MeshBuilder.addPrimitiveFlipped(state, Mat4.id, circle)
     }
@@ -277,10 +285,11 @@ function buildSectorMesh(data: DihedralData, props: DihedralProps, mesh?: Mesh):
 
 function getSectorShape(ctx: RuntimeContext, data: DihedralData, props: DihedralProps, shape?: Shape<Mesh>) {
     const mesh = buildSectorMesh(data, props, shape && shape.geometry);
+    const name = getDihedralName(data)
     const getLabel = function (groupId: number ) {
-        return dihedralLabel(data.quads[groupId], props.arcScale)
+        return dihedralLabel(data.quads[groupId])
     }
-    return Shape.create('Dihedral Sector', data, mesh, () => props.color, () => 1, getLabel)
+    return Shape.create(name, data, mesh, () => props.color, () => 1, getLabel)
 }
 
 //
@@ -303,10 +312,11 @@ function buildText(data: DihedralData, props: DihedralProps, text?: Text): Text
 
 function getTextShape(ctx: RuntimeContext, data: DihedralData, props: DihedralProps, shape?: Shape<Text>) {
     const text = buildText(data, props, shape && shape.geometry);
+    const name = getDihedralName(data)
     const getLabel = function (groupId: number ) {
-        return dihedralLabel(data.quads[groupId], props.arcScale)
+        return dihedralLabel(data.quads[groupId])
     }
-    return Shape.create('Dihedral Text', data, text, () => props.textColor, () => props.textSize, getLabel)
+    return Shape.create(name, data, text, () => props.textColor, () => props.textSize, getLabel)
 }
 
 //

+ 8 - 2
src/mol-repr/shape/loci/distance.ts

@@ -94,6 +94,10 @@ function distanceLabel(pair: Loci.Bundle<2>, unitLabel: string) {
     return `Distance ${tmpState.distance.toFixed(2)} ${unitLabel}`
 }
 
+function getDistanceName(data: DistanceData, unitLabel: string) {
+    return data.pairs.length === 1 ? distanceLabel(data.pairs[0], unitLabel) : `${data.pairs.length} Distances`
+}
+
 //
 
 function buildLines(data: DistanceData, props: DistanceProps, lines?: Lines): Lines {
@@ -107,10 +111,11 @@ function buildLines(data: DistanceData, props: DistanceProps, lines?: Lines): Li
 
 function getLinesShape(ctx: RuntimeContext, data: DistanceData, props: DistanceProps, shape?: Shape<Lines>) {
     const lines = buildLines(data, props, shape && shape.geometry);
+    const name = getDistanceName(data, props.unitLabel)
     const getLabel = function (groupId: number ) {
         return distanceLabel(data.pairs[groupId], props.unitLabel)
     }
-    return Shape.create('Distance Lines', data, lines, () => props.linesColor, () => props.linesSize, getLabel)
+    return Shape.create(name, data, lines, () => props.linesColor, () => props.linesSize, getLabel)
 }
 
 //
@@ -128,10 +133,11 @@ function buildText(data: DistanceData, props: DistanceProps, text?: Text): Text
 
 function getTextShape(ctx: RuntimeContext, data: DistanceData, props: DistanceProps, shape?: Shape<Text>) {
     const text = buildText(data, props, shape && shape.geometry);
+    const name = getDistanceName(data, props.unitLabel)
     const getLabel = function (groupId: number ) {
         return distanceLabel(data.pairs[groupId], props.unitLabel)
     }
-    return Shape.create('Distance Text', data, text, () => props.textColor, () => props.textSize, getLabel)
+    return Shape.create(name, data, text, () => props.textColor, () => props.textSize, getLabel)
 }
 
 //

+ 17 - 6
src/mol-repr/shape/loci/label.ts

@@ -47,25 +47,36 @@ export type LabelProps = PD.Values<LabelParams>
 
 const tmpSphere = Sphere3D()
 
+function label(info: { loci: Loci, label?: string }) {
+    return info.label || lociLabel(info.loci, { hidePrefix: true, htmlStyling: false })
+}
+
+function getLabelName(data: LabelData) {
+    return data.infos.length === 1 ? label(data.infos[0]) : `${data.infos.length} Labels`
+}
+
+//
+
 function buildText(data: LabelData, props: LabelProps, text?: Text): Text {
     const builder = TextBuilder.create(props, 128, 64, text)
     for (let i = 0, il = data.infos.length; i < il; ++i) {
-        const d = data.infos[i]
-        const sphere = Loci.getBoundingSphere(d.loci, tmpSphere)
+        const info = data.infos[i]
+        const sphere = Loci.getBoundingSphere(info.loci, tmpSphere)
         if (!sphere) continue
         const { center, radius } = sphere
-        const label = d.label || lociLabel(d.loci, { hidePrefix: true, htmlStyling: false })
-        builder.add(label, center[0], center[1], center[2], radius, 1, i)
+        const text = label(info)
+        builder.add(text, center[0], center[1], center[2], radius, 1, i)
     }
     return builder.getText()
 }
 
 function getTextShape(ctx: RuntimeContext, data: LabelData, props: LabelProps, shape?: Shape<Text>) {
     const text = buildText(data, props, shape && shape.geometry);
+    const name = getLabelName(data)
     const getLabel = function (groupId: number) {
-        return 'Label Text'
+        return label(data.infos[groupId])
     }
-    return Shape.create('Label Text', data, text, () => props.textColor, () => props.textSize, getLabel)
+    return Shape.create(name, data, text, () => props.textColor, () => props.textSize, getLabel)
 }
 
 //

+ 54 - 33
src/mol-repr/shape/loci/orientation.ts

@@ -14,7 +14,6 @@ import { Representation, RepresentationParamsGetter, RepresentationContext } fro
 import { Shape } from '../../../mol-model/shape';
 import { Mesh } from '../../../mol-geo/geometry/mesh/mesh';
 import { MeshBuilder } from '../../../mol-geo/geometry/mesh/mesh-builder';
-import { PrincipalAxes } from '../../../mol-math/linear-algebra/matrix/principal-axes';
 import { lociLabel } from '../../../mol-theme/label';
 import { addAxes } from '../../../mol-geo/geometry/mesh/builder/axes';
 import { addOrientedBox } from '../../../mol-geo/geometry/mesh/builder/box';
@@ -23,7 +22,7 @@ import { Axes3D } from '../../../mol-math/geometry';
 import { Vec3 } from '../../../mol-math/linear-algebra';
 
 export interface OrientationData {
-    loci: Loci
+    locis: Loci[]
 }
 
 const SharedParams = {
@@ -69,66 +68,88 @@ export type OrientationProps = PD.Values<OrientationParams>
 
 //
 
-function buildAxesMesh(principalAxes: PrincipalAxes, props: OrientationProps, mesh?: Mesh): Mesh {
+function orientationLabel(loci: Loci) {
+    const label = lociLabel(loci, { countsOnly: true })
+    return `Principal Axes of ${label}`
+}
+
+function getOrientationName(data: OrientationData) {
+    return data.locis.length === 1 ? orientationLabel(data.locis[0]) : `${data.locis.length} Orientations`
+}
+
+//
+
+function buildAxesMesh(data: OrientationData, props: OrientationProps, mesh?: Mesh): Mesh {
     const state = MeshBuilder.createState(256, 128, mesh)
-    state.currentGroup = 1
-    addAxes(state, principalAxes.momentsAxes, props.scale, 2, 20)
+    for (let i = 0, il = data.locis.length; i < il; ++i) {
+        const principalAxes = Loci.getPrincipalAxes(data.locis[i])
+        if (principalAxes) {
+            state.currentGroup = i
+            addAxes(state, principalAxes.momentsAxes, props.scale, 2, 20)
+        }
+    }
     return MeshBuilder.getMesh(state)
 }
 
 function getAxesShape(ctx: RuntimeContext, data: OrientationData, props: OrientationProps, shape?: Shape<Mesh>) {
-    const label = lociLabel(data.loci, { countsOnly: true })
-    const principalAxes = Loci.getPrincipalAxes(data.loci)
-    const mesh = principalAxes ? buildAxesMesh(principalAxes, props, shape && shape.geometry) : Mesh.createEmpty(shape && shape.geometry);
+    const mesh = buildAxesMesh(data, props, shape && shape.geometry);
+    const name = getOrientationName(data)
     const getLabel = function (groupId: number ) {
-        return `Principal Axes of ${label}`
+        return orientationLabel(data.locis[groupId])
     }
-    return Shape.create('Principal Axes', data, mesh, () => props.color, () => 1, getLabel)
+    return Shape.create(name, data, mesh, () => props.color, () => 1, getLabel)
 }
 
 //
 
-function buildBoxMesh(principalAxes: PrincipalAxes, props: OrientationProps, mesh?: Mesh): Mesh {
+function buildBoxMesh(data: OrientationData, props: OrientationProps, mesh?: Mesh): Mesh {
     const state = MeshBuilder.createState(256, 128, mesh)
-    state.currentGroup = 1
-    addOrientedBox(state, principalAxes.boxAxes, props.scale, 2, 20)
+    for (let i = 0, il = data.locis.length; i < il; ++i) {
+        const principalAxes = Loci.getPrincipalAxes(data.locis[i])
+        if (principalAxes) {
+            state.currentGroup = i
+            addOrientedBox(state, principalAxes.boxAxes, props.scale, 2, 20)
+        }
+    }
     return MeshBuilder.getMesh(state)
 }
 
 function getBoxShape(ctx: RuntimeContext, data: OrientationData, props: OrientationProps, shape?: Shape<Mesh>) {
-    const label = lociLabel(data.loci, { countsOnly: true })
-    const principalAxes = Loci.getPrincipalAxes(data.loci)
-    const mesh = principalAxes ? buildBoxMesh(principalAxes, props, shape && shape.geometry) : Mesh.createEmpty(shape && shape.geometry);
+    const mesh = buildBoxMesh(data, props, shape && shape.geometry);
+    const name = getOrientationName(data)
     const getLabel = function (groupId: number ) {
-        return `Oriented Box of ${label}`
+        return orientationLabel(data.locis[groupId])
     }
-    return Shape.create('Oriented Box', data, mesh, () => props.color, () => 1, getLabel)
+    return Shape.create(name, data, mesh, () => props.color, () => 1, getLabel)
 }
 
 //
 
-function buildEllipsoidMesh(principalAxes: PrincipalAxes, props: OrientationProps, mesh?: Mesh): Mesh {
+function buildEllipsoidMesh(data: OrientationData, props: OrientationProps, mesh?: Mesh): Mesh {
     const state = MeshBuilder.createState(256, 128, mesh)
-
-    const axes = principalAxes.boxAxes
-    const { origin, dirA, dirB } = axes
-    const size = Axes3D.size(Vec3(), axes)
-    Vec3.scale(size, size, 0.5)
-    const radiusScale = Vec3.create(size[2], size[1], size[0])
-
-    state.currentGroup = 1
-    addEllipsoid(state, origin, dirA, dirB, radiusScale, 2)
+    for (let i = 0, il = data.locis.length; i < il; ++i) {
+        const principalAxes = Loci.getPrincipalAxes(data.locis[i])
+        if (principalAxes) {
+            const axes = principalAxes.boxAxes
+            const { origin, dirA, dirB } = axes
+            const size = Axes3D.size(Vec3(), axes)
+            Vec3.scale(size, size, 0.5)
+            const radiusScale = Vec3.create(size[2], size[1], size[0])
+
+            state.currentGroup = i
+            addEllipsoid(state, origin, dirA, dirB, radiusScale, 2)
+        }
+    }
     return MeshBuilder.getMesh(state)
 }
 
 function getEllipsoidShape(ctx: RuntimeContext, data: OrientationData, props: OrientationProps, shape?: Shape<Mesh>) {
-    const label = lociLabel(data.loci, { countsOnly: true })
-    const principalAxes = Loci.getPrincipalAxes(data.loci)
-    const mesh = principalAxes ? buildEllipsoidMesh(principalAxes, props, shape && shape.geometry) : Mesh.createEmpty(shape && shape.geometry);
+    const mesh = buildEllipsoidMesh(data, props, shape && shape.geometry);
+    const name = getOrientationName(data)
     const getLabel = function (groupId: number ) {
-        return `Ellipsoid of ${label}`
+        return orientationLabel(data.locis[groupId])
     }
-    return Shape.create('Ellipsoid', data, mesh, () => props.color, () => 1, getLabel)
+    return Shape.create(name, data, mesh, () => props.color, () => 1, getLabel)
 }
 
 //