Browse Source

improved labels in measurement representations

Alexander Rose 5 years ago
parent
commit
9fa5d40306

+ 18 - 15
src/mol-repr/shape/loci/angle.ts

@@ -23,6 +23,7 @@ import { Circle } from '../../../mol-geo/primitive/circle';
 import { transformPrimitive } from '../../../mol-geo/primitive/primitive';
 import { MarkerActions, MarkerAction } from '../../../mol-util/marker-action';
 import { angleLabel } from '../../../mol-theme/label';
+import { Sphere3D } from '../../../mol-math/geometry';
 
 export interface AngleData {
     triples: Loci.Bundle<3>[]
@@ -88,9 +89,9 @@ export type AngleProps = PD.Values<AngleParams>
 
 function getAngleState() {
     return {
-        pointA: Vec3(),
-        pointB: Vec3(),
-        pointC: Vec3(),
+        sphereA: Sphere3D(),
+        sphereB: Sphere3D(),
+        sphereC: Sphere3D(),
 
         arcDirA: Vec3(),
         arcDirC: Vec3(),
@@ -106,16 +107,16 @@ const tmpVec = Vec3()
 const tmpMat = Mat4()
 
 function setAngleState(triple: Loci.Bundle<3>, state: AngleState, arcScale: number) {
-    const { pointA, pointB, pointC } = state
+    const { sphereA, sphereB, sphereC } = state
     const { arcDirA, arcDirC, arcNormal } = state
 
     const [lociA, lociB, lociC] = triple.loci
-    Loci.getCenter(lociA, pointA)
-    Loci.getCenter(lociB, pointB)
-    Loci.getCenter(lociC, pointC)
+    Loci.getBoundingSphere(lociA, sphereA)
+    Loci.getBoundingSphere(lociB, sphereB)
+    Loci.getBoundingSphere(lociC, sphereC)
 
-    Vec3.sub(arcDirA, pointA, pointB)
-    Vec3.sub(arcDirC, pointC, pointB)
+    Vec3.sub(arcDirA, sphereA.center, sphereB.center)
+    Vec3.sub(arcDirC, sphereC.center, sphereB.center)
     Vec3.cross(arcNormal, arcDirA, arcDirC)
 
     const len = Math.min(Vec3.magnitude(arcDirA), Vec3.magnitude(arcDirC))
@@ -131,8 +132,8 @@ function getCircle(state: AngleState, segmentLength?: number) {
     const { radius, angle } = state
     const segments = segmentLength ? arcLength(angle, radius) / segmentLength : 32
 
-    Mat4.targetTo(tmpMat, state.pointB, state.pointA, state.arcNormal)
-    Mat4.setTranslation(tmpMat, state.pointB)
+    Mat4.targetTo(tmpMat, state.sphereB.center, state.sphereA.center, state.arcNormal)
+    Mat4.setTranslation(tmpMat, state.sphereB.center)
     Mat4.mul(tmpMat, tmpMat, Mat4.rotY180)
 
     const circle = Circle({ radius, thetaLength: angle, segments })
@@ -151,8 +152,8 @@ function buildVectorsLines(data: AngleData, props: AngleProps, lines?: Lines): L
     const builder = LinesBuilder.create(128, 64, lines)
     for (let i = 0, il = data.triples.length; i < il; ++i) {
         setAngleState(data.triples[i], tmpState, props.arcScale)
-        builder.addFixedLengthDashes(tmpState.pointB, tmpState.pointA, props.dashLength, i)
-        builder.addFixedLengthDashes(tmpState.pointB, tmpState.pointC, props.dashLength, i)
+        builder.addFixedLengthDashes(tmpState.sphereB.center, tmpState.sphereA.center, props.dashLength, i)
+        builder.addFixedLengthDashes(tmpState.sphereB.center, tmpState.sphereC.center, props.dashLength, i)
     }
     return builder.getLines()
 }
@@ -223,11 +224,13 @@ function buildText(data: AngleData, props: AngleProps, text?: Text): Text {
 
         Vec3.add(tmpVec, tmpState.arcDirA, tmpState.arcDirC)
         Vec3.setMagnitude(tmpVec, tmpVec, tmpState.radius)
-        Vec3.add(tmpVec, tmpState.pointB, tmpVec)
+        Vec3.add(tmpVec, tmpState.sphereB.center, tmpVec)
 
         const angle = radToDeg(tmpState.angle).toFixed(2)
         const label = `${angle}\u00B0`
-        builder.add(label, tmpVec[0], tmpVec[1], tmpVec[2], 0.1, 1, i)
+        const radius = Math.max(2, tmpState.sphereA.radius, tmpState.sphereB.radius, tmpState.sphereC.radius)
+        const scale = radius / 2
+        builder.add(label, tmpVec[0], tmpVec[1], tmpVec[2], 0.1, scale, i)
     }
     return builder.getText()
 }

+ 1 - 1
src/mol-repr/shape/loci/common.ts

@@ -10,5 +10,5 @@ import { ColorNames } from '../../../mol-util/color/names';
 
 export const MeasurementRepresentationCommonTextParams = {
     textColor: PD.Color(ColorNames.black, { isEssential: true }),
-    textSize: PD.Numeric(0.4, { min: 0.1, max: 5, step: 0.1 }, { isEssential: true }),
+    textSize: PD.Numeric(0.5, { min: 0.1, max: 5, step: 0.1 }, { isEssential: true }),
 }

+ 21 - 18
src/mol-repr/shape/loci/dihedral.ts

@@ -24,6 +24,7 @@ import { transformPrimitive } from '../../../mol-geo/primitive/primitive';
 import { MarkerActions, MarkerAction } from '../../../mol-util/marker-action';
 import { dihedralLabel } from '../../../mol-theme/label';
 import { MeasurementRepresentationCommonTextParams } from './common';
+import { Sphere3D } from '../../../mol-math/geometry';
 
 export interface DihedralData {
     quads: Loci.Bundle<4>[]
@@ -95,10 +96,10 @@ export type DihedralProps = PD.Values<DihedralParams>
 
 function getDihedralState() {
     return {
-        pointA: Vec3(),
-        pointB: Vec3(),
-        pointC: Vec3(),
-        pointD: Vec3(),
+        sphereA: Sphere3D(),
+        sphereB: Sphere3D(),
+        sphereC: Sphere3D(),
+        sphereD: Sphere3D(),
 
         dirBA: Vec3(),
         dirCD: Vec3(),
@@ -124,24 +125,24 @@ const tmpMat = Mat4()
 
 // TODO improper dihedrals are not handled correctly
 function setDihedralState(quad: Loci.Bundle<4>, state: DihedralState, arcScale: number) {
-    const { pointA, pointB, pointC, pointD, dirBA, dirCD, projA, projD } = state
+    const { sphereA, sphereB, sphereC, sphereD, dirBA, dirCD, projA, projD } = state
     const { arcPointA, arcPointD, arcDirA, arcDirD, arcCenter, arcNormal } = state
 
     const [lociA, lociB, lociC, lociD] = quad.loci
-    Loci.getCenter(lociA, pointA)
-    Loci.getCenter(lociB, pointB)
-    Loci.getCenter(lociC, pointC)
-    Loci.getCenter(lociD, pointD)
+    Loci.getBoundingSphere(lociA, sphereA)
+    Loci.getBoundingSphere(lociB, sphereB)
+    Loci.getBoundingSphere(lociC, sphereC)
+    Loci.getBoundingSphere(lociD, sphereD)
 
-    Vec3.add(arcCenter, pointB, pointC)
+    Vec3.add(arcCenter, sphereB.center, sphereC.center)
     Vec3.scale(arcCenter, arcCenter, 0.5)
 
-    Vec3.sub(dirBA, pointA, pointB)
-    Vec3.sub(dirCD, pointD, pointC)
+    Vec3.sub(dirBA, sphereA.center, sphereB.center)
+    Vec3.sub(dirCD, sphereD.center, sphereC.center)
     Vec3.add(arcPointA, arcCenter, dirBA)
     Vec3.add(arcPointD, arcCenter, dirCD)
 
-    Vec3.sub(arcNormal, pointC, pointB)
+    Vec3.sub(arcNormal, sphereC.center, sphereB.center)
     Vec3.orthogonalize(arcDirA, arcNormal, dirBA)
     Vec3.orthogonalize(arcDirD, arcNormal, dirCD)
 
@@ -157,15 +158,15 @@ function setDihedralState(quad: Loci.Bundle<4>, state: DihedralState, arcScale:
     state.radius = radius
     state.angle = Vec3.angle(arcDirA, arcDirD)
 
-    Vec3.matchDirection(tmpVec, arcNormal, Vec3.sub(tmpVec, arcPointA, pointA))
+    Vec3.matchDirection(tmpVec, arcNormal, Vec3.sub(tmpVec, arcPointA, sphereA.center))
     const angleA = Vec3.angle(dirBA, tmpVec)
     const lenA = radius / Math.cos(angleA > halfPI ? angleA - halfPI : angleA)
-    Vec3.add(projA, pointB, Vec3.setMagnitude(tmpVec, dirBA, lenA))
+    Vec3.add(projA, sphereB.center, Vec3.setMagnitude(tmpVec, dirBA, lenA))
 
-    Vec3.matchDirection(tmpVec, arcNormal, Vec3.sub(tmpVec, arcPointD, pointD))
+    Vec3.matchDirection(tmpVec, arcNormal, Vec3.sub(tmpVec, arcPointD, sphereD.center))
     const angleD = Vec3.angle(dirCD, tmpVec)
     const lenD = radius / Math.cos(angleD > halfPI ? angleD - halfPI : angleD)
-    Vec3.add(projD, pointC, Vec3.setMagnitude(tmpVec, dirCD, lenD))
+    Vec3.add(projD, sphereC.center, Vec3.setMagnitude(tmpVec, dirCD, lenD))
 
     return state
 }
@@ -288,7 +289,9 @@ function buildText(data: DihedralData, props: DihedralProps, text?: Text): Text
 
         const angle = radToDeg(tmpState.angle).toFixed(2)
         const label = `${angle}\u00B0`
-        builder.add(label, tmpVec[0], tmpVec[1], tmpVec[2], 0.1, 1, i)
+        const radius = Math.max(2, tmpState.sphereA.radius, tmpState.sphereB.radius, tmpState.sphereC.radius, tmpState.sphereD.radius)
+        const scale = radius / 2
+        builder.add(label, tmpVec[0], tmpVec[1], tmpVec[2], 0.1, scale, i)
     }
     return builder.getText()
 }

+ 13 - 10
src/mol-repr/shape/loci/distance.ts

@@ -19,6 +19,7 @@ import { Vec3 } from '../../../mol-math/linear-algebra';
 import { MarkerActions, MarkerAction } from '../../../mol-util/marker-action';
 import { distanceLabel } from '../../../mol-theme/label';
 import { MeasurementRepresentationCommonTextParams } from './common';
+import { Sphere3D } from '../../../mol-math/geometry';
 
 export interface DistanceData {
     pairs: Loci.Bundle<2>[]
@@ -63,8 +64,8 @@ export type DistanceProps = PD.Values<DistanceParams>
 
 function getDistanceState() {
     return {
-        pointA: Vec3(),
-        pointB: Vec3(),
+        sphereA: Sphere3D(),
+        sphereB: Sphere3D(),
 
         center: Vec3(),
         distance: 0,
@@ -73,15 +74,15 @@ function getDistanceState() {
 type DistanceState = ReturnType<typeof getDistanceState>
 
 function setDistanceState(pair: Loci.Bundle<2>, state: DistanceState) {
-    const { pointA, pointB, center } = state
+    const { sphereA, sphereB, center } = state
 
     const [lociA, lociB] = pair.loci
-    Loci.getCenter(lociA, pointA)
-    Loci.getCenter(lociB, pointB)
+    Loci.getBoundingSphere(lociA, sphereA)
+    Loci.getBoundingSphere(lociB, sphereB)
 
-    Vec3.add(center, pointA, pointB)
+    Vec3.add(center, sphereA.center, sphereB.center)
     Vec3.scale(center, center, 0.5)
-    state.distance = Vec3.distance(pointA, pointB)
+    state.distance = Vec3.distance(sphereA.center, sphereB.center)
 
     return state
 }
@@ -98,7 +99,7 @@ function buildLines(data: DistanceData, props: DistanceProps, lines?: Lines): Li
     const builder = LinesBuilder.create(128, 64, lines)
     for (let i = 0, il = data.pairs.length; i < il; ++i) {
         setDistanceState(data.pairs[i], tmpState)
-        builder.addFixedLengthDashes(tmpState.pointA, tmpState.pointB, props.dashLength, i)
+        builder.addFixedLengthDashes(tmpState.sphereA.center, tmpState.sphereB.center, props.dashLength, i)
     }
     return builder.getLines()
 }
@@ -116,9 +117,11 @@ function buildText(data: DistanceData, props: DistanceProps, text?: Text): Text
     const builder = TextBuilder.create(props, 128, 64, text)
     for (let i = 0, il = data.pairs.length; i < il; ++i) {
         setDistanceState(data.pairs[i], tmpState)
-        const { center, distance } = tmpState
+        const { center, distance, sphereA, sphereB } = tmpState
         const label = `${distance.toFixed(2)} ${props.unitLabel}`
-        builder.add(label, center[0], center[1], center[2], 1, 1, i)
+        const radius = Math.max(2, sphereA.radius, sphereB.radius)
+        const scale = radius / 2
+        builder.add(label, center[0], center[1], center[2], 1, scale, i)
     }
     return builder.getText()
 }

+ 4 - 4
src/mol-repr/shape/loci/label.ts

@@ -44,8 +44,8 @@ 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 label(info: { loci: Loci, label?: string }, condensed = false) {
+    return info.label || lociLabel(info.loci, { hidePrefix: true, htmlStyling: false, condensed })
 }
 
 function getLabelName(data: LabelData) {
@@ -61,8 +61,8 @@ function buildText(data: LabelData, props: LabelProps, text?: Text): Text {
         const sphere = Loci.getBoundingSphere(info.loci, tmpSphere)
         if (!sphere) continue
         const { center, radius } = sphere
-        const text = label(info)
-        builder.add(text, center[0], center[1], center[2], radius, 1, i)
+        const text = label(info, true)
+        builder.add(text, center[0], center[1], center[2], radius / 0.9, Math.max(1, radius), i)
     }
     return builder.getText()
 }