Browse Source

Dihedrals: fix arcs and labels

David Sehnal 5 years ago
parent
commit
2dacfcb485
2 changed files with 24 additions and 5 deletions
  1. 23 4
      src/mol-repr/shape/loci/dihedral.ts
  2. 1 1
      src/mol-theme/label.ts

+ 23 - 4
src/mol-repr/shape/loci/dihedral.ts

@@ -76,6 +76,7 @@ type TextParams = typeof TextParams
 const DihedralVisuals = {
     'vectors': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<DihedralData, VectorsParams>) => ShapeRepresentation(getVectorsShape, Lines.Utils, { modifyState: s => ({ ...s, pickable: false }) }),
     'extenders': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<DihedralData, ExtendersParams>) => ShapeRepresentation(getExtendersShape, Lines.Utils, { modifyState: s => ({ ...s, pickable: false }) }),
+    'connector': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<DihedralData, ExtendersParams>) => ShapeRepresentation(getConnectorShape, Lines.Utils, { modifyState: s => ({ ...s, pickable: false }) }),
     'arc': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<DihedralData, ArcParams>) => ShapeRepresentation(getArcShape, Lines.Utils, { modifyState: s => ({ ...s, pickable: false }) }),
     'sector': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<DihedralData, SectorParams>) => ShapeRepresentation(getSectorShape, Mesh.Utils, { modifyProps: p => ({ ...p, alpha: p.sectorOpacity }), modifyState: s => ({ ...s, markerActions: MarkerActions.Highlighting }) }),
     'text': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<DihedralData, TextParams>) => ShapeRepresentation(getTextShape, Text.Utils, { modifyState: s => ({ ...s, markerActions: MarkerAction.None }) }),
@@ -156,7 +157,8 @@ function setDihedralState(quad: Loci.Bundle<4>, state: DihedralState, arcScale:
     Vec3.add(arcPointA, arcCenter, arcDirA);
     Vec3.add(arcPointD, arcCenter, arcDirD);
     state.radius = radius;
-    state.angle = Vec3.angle(arcDirA, arcDirD);
+
+    state.angle = Vec3.dihedralAngle(sphereA.center, sphereB.center, sphereC.center, sphereD.center);
 
     Vec3.matchDirection(tmpVec, arcNormal, Vec3.sub(tmpVec, arcPointA, sphereA.center));
     const angleA = Vec3.angle(dirBA, tmpVec);
@@ -175,11 +177,11 @@ function getCircle(state: DihedralState, segmentLength?: number) {
     const { radius, angle } = state;
     const segments = segmentLength ? arcLength(angle, radius) / segmentLength : 32;
 
-    Mat4.targetTo(tmpMat, state.arcCenter, angle > halfPI ? state.arcPointA : state.arcPointD, state.arcNormal);
+    Mat4.targetTo(tmpMat, state.arcCenter, angle < 0 ? state.arcPointD : state.arcPointA, state.arcNormal);
     Mat4.setTranslation(tmpMat, state.arcCenter);
     Mat4.mul(tmpMat, tmpMat, Mat4.rotY180);
 
-    const circle = Circle({ radius, thetaLength: angle, segments });
+    const circle = Circle({ radius, thetaLength: Math.abs(angle), segments });
     return transformPrimitive(circle, tmpMat);
 }
 
@@ -209,6 +211,23 @@ function getVectorsShape(ctx: RuntimeContext, data: DihedralData, props: Dihedra
 
 //
 
+function buildConnectorLine(data: DihedralData, props: DihedralProps, lines?: Lines): Lines {
+    const builder = LinesBuilder.create(128, 64, lines);
+    for (let i = 0, il = data.quads.length; i < il; ++i) {
+        setDihedralState(data.quads[i], tmpState, props.arcScale);
+        builder.addFixedLengthDashes(tmpState.sphereB.center, tmpState.sphereC.center, props.dashLength, i);
+    }
+    return builder.getLines();
+}
+
+function getConnectorShape(ctx: RuntimeContext, data: DihedralData, props: DihedralProps, shape?: Shape<Lines>) {
+    const lines = buildConnectorLine(data, props, shape && shape.geometry);
+    const name = getDihedralName(data);
+    return Shape.create(name, data, lines, () => props.color, () => props.linesSize, () => '');
+}
+
+//
+
 function buildExtendersLines(data: DihedralData, props: DihedralProps, lines?: Lines): Lines {
     const builder = LinesBuilder.create(128, 64, lines);
     for (let i = 0, il = data.quads.length; i < il; ++i) {
@@ -287,7 +306,7 @@ function buildText(data: DihedralData, props: DihedralProps, text?: Text): Text
         Vec3.setMagnitude(tmpVec, tmpVec, tmpState.radius);
         Vec3.add(tmpVec, tmpState.arcCenter, tmpVec);
 
-        const angle = radToDeg(tmpState.angle).toFixed(2);
+        const angle = Math.abs(radToDeg(tmpState.angle)).toFixed(2);
         const label = `${angle}\u00B0`;
         const radius = Math.max(2, tmpState.sphereA.radius, tmpState.sphereB.radius, tmpState.sphereC.radius, tmpState.sphereD.radius);
         const scale = radius / 2;

+ 1 - 1
src/mol-theme/label.ts

@@ -330,7 +330,7 @@ export function angleLabel(triple: Loci.Bundle<3>, options: Partial<LabelOptions
 export function dihedralLabel(quad: Loci.Bundle<4>, options: Partial<LabelOptions & { measureOnly: boolean }> = {}) {
     const o = { ...DefaultLabelOptions, measureOnly: false, ...options };
     const [cA, cB, cC, cD] = quad.loci.map(l => Loci.getCenter(l)!);
-    const dihedral = `${radToDeg(Vec3.dihedralAngle(cA, cB, cC, cD)).toFixed(2)}\u00B0`;
+    const dihedral = `${Math.abs(radToDeg(Vec3.dihedralAngle(cA, cB, cC, cD))).toFixed(2)}\u00B0`;
     if (o.measureOnly) return dihedral;
     const label = bundleLabel(quad, o);
     return o.condensed ? `${dihedral} | ${label}` : `Dihedral ${dihedral}</br>${label}`;