diff --git a/src/mol-geo/representation/structure/cartoon.ts b/src/mol-geo/representation/structure/cartoon.ts index 359709b5d9c8b0a6667124581611a910d8b6b7b6..3e56c507a491bc014221ef1811db9b94e7d00aa1 100644 --- a/src/mol-geo/representation/structure/cartoon.ts +++ b/src/mol-geo/representation/structure/cartoon.ts @@ -13,11 +13,13 @@ import { MarkerAction } from '../../util/marker-data'; import { PolymerTraceVisual, DefaultPolymerTraceProps } from './visual/polymer-trace-mesh'; import { PolymerGapVisual, DefaultPolymerGapProps } from './visual/polymer-gap-cylinder'; import { NucleotideBlockVisual, DefaultNucleotideBlockProps } from './visual/nucleotide-block-mesh'; +import { PolymerDirectionVisual, DefaultPolymerDirectionProps } from './visual/polymer-direction-wedge'; export const DefaultCartoonProps = { ...DefaultPolymerTraceProps, ...DefaultPolymerGapProps, - ...DefaultNucleotideBlockProps + ...DefaultNucleotideBlockProps, + ...DefaultPolymerDirectionProps } export type CartoonProps = Partial<typeof DefaultCartoonProps> @@ -25,13 +27,14 @@ export function CartoonRepresentation(): StructureRepresentation<CartoonProps> { const traceRepr = StructureUnitsRepresentation(PolymerTraceVisual) const gapRepr = StructureUnitsRepresentation(PolymerGapVisual) const blockRepr = StructureUnitsRepresentation(NucleotideBlockVisual) + const directionRepr = StructureUnitsRepresentation(PolymerDirectionVisual) return { get renderObjects() { - return [ ...traceRepr.renderObjects, ...gapRepr.renderObjects, ...blockRepr.renderObjects ] + return [ ...traceRepr.renderObjects, ...gapRepr.renderObjects, ...blockRepr.renderObjects, ...directionRepr.renderObjects ] }, get props() { - return { ...traceRepr.props, ...gapRepr.props, ...blockRepr.props } + return { ...traceRepr.props, ...gapRepr.props, ...blockRepr.props, ...directionRepr.props } }, create: (structure: Structure, props: CartoonProps = {} as CartoonProps) => { const p = Object.assign({}, DefaultCartoonProps, props) @@ -39,6 +42,7 @@ export function CartoonRepresentation(): StructureRepresentation<CartoonProps> { await traceRepr.create(structure, p).runInContext(ctx) await gapRepr.create(structure, p).runInContext(ctx) await blockRepr.create(structure, p).runInContext(ctx) + await directionRepr.create(structure, p).runInContext(ctx) }) }, update: (props: CartoonProps) => { @@ -47,25 +51,30 @@ export function CartoonRepresentation(): StructureRepresentation<CartoonProps> { await traceRepr.update(p).runInContext(ctx) await gapRepr.update(p).runInContext(ctx) await blockRepr.update(p).runInContext(ctx) + await directionRepr.update(p).runInContext(ctx) }) }, getLoci: (pickingId: PickingId) => { const traceLoci = traceRepr.getLoci(pickingId) const gapLoci = gapRepr.getLoci(pickingId) const blockLoci = blockRepr.getLoci(pickingId) + const directionLoci = directionRepr.getLoci(pickingId) return !isEmptyLoci(traceLoci) ? traceLoci : !isEmptyLoci(gapLoci) ? gapLoci - : blockLoci + : !isEmptyLoci(blockLoci) ? blockLoci + : directionLoci }, mark: (loci: Loci, action: MarkerAction) => { traceRepr.mark(loci, action) gapRepr.mark(loci, action) blockRepr.mark(loci, action) + directionRepr.mark(loci, action) }, destroy() { traceRepr.destroy() gapRepr.destroy() blockRepr.destroy() + directionRepr.destroy() } } } \ No newline at end of file diff --git a/src/mol-geo/representation/structure/visual/polymer-direction-wedge.ts b/src/mol-geo/representation/structure/visual/polymer-direction-wedge.ts new file mode 100644 index 0000000000000000000000000000000000000000..8cea9508887e465e487f69d2b3a98909fdf0a989 --- /dev/null +++ b/src/mol-geo/representation/structure/visual/polymer-direction-wedge.ts @@ -0,0 +1,176 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { ValueCell } from 'mol-util/value-cell' + +import { createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object' +import { Unit, StructureElement } from 'mol-model/structure'; +import { DefaultStructureProps, UnitsVisual } from '..'; +import { RuntimeContext } from 'mol-task' +import { createTransforms, createColors } from './util/common'; +import { markElement } from './util/element'; +import { deepEqual } from 'mol-util'; +import { MeshValues } from 'mol-gl/renderable'; +import { getMeshData } from '../../../util/mesh-data'; +import { Mesh } from '../../../shape/mesh'; +import { PickingId } from '../../../util/picking'; +import { OrderedSet } from 'mol-data/int'; +import { createMarkers, MarkerAction } from '../../../util/marker-data'; +import { Loci, EmptyLoci } from 'mol-model/loci'; +import { SizeTheme } from '../../../theme'; +import { createMeshValues, updateMeshValues, updateRenderableState, createRenderableState, DefaultMeshProps } from '../../util'; +import { MeshBuilder } from '../../../shape/mesh-builder'; +import { getPolymerElementCount, PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment } from './util/polymer'; +import { Vec3, Mat4 } from 'mol-math/linear-algebra'; +import { SecondaryStructureType, MoleculeType } from 'mol-model/structure/model/types'; + +const t = Mat4.identity() + +async function createPolymerDirectionWedgeMesh(ctx: RuntimeContext, unit: Unit, mesh?: Mesh) { + const polymerElementCount = getPolymerElementCount(unit) + console.log('polymerElementCount direction', polymerElementCount) + if (!polymerElementCount) return Mesh.createEmpty(mesh) + + // TODO better vertex count estimates + const builder = MeshBuilder.create(polymerElementCount * 30, polymerElementCount * 30 / 2, mesh) + const linearSegments = 1 + + const state = createCurveSegmentState(linearSegments) + const { normalVectors, binormalVectors } = state + + let i = 0 + const polymerTraceIt = PolymerTraceIterator(unit) + while (polymerTraceIt.hasNext) { + const v = polymerTraceIt.move() + builder.setId(v.center.element) + + const isNucleic = v.moleculeType === MoleculeType.DNA || v.moleculeType === MoleculeType.RNA + const isSheet = SecondaryStructureType.is(v.secStrucType, SecondaryStructureType.Flag.Beta) + const tension = (isNucleic || isSheet) ? 0.5 : 0.9 + + // console.log('ELEMENT', i) + interpolateCurveSegment(state, v, tension) + + if ((isSheet && !v.secStrucChange) || !isSheet) { + const upVec = Vec3.zero() + let width = 0.5, height = 1.2, depth = 0.6 + if (isNucleic) { + Vec3.fromArray(upVec, binormalVectors, Math.round(linearSegments / 2) * 3) + depth = 0.9 + } else { + Vec3.fromArray(upVec, normalVectors, Math.round(linearSegments / 2) * 3) + } + + Mat4.targetTo(t, v.p3, v.p1, upVec) + Mat4.mul(t, t, Mat4.rotXY90) + Mat4.setTranslation(t, v.p2) + builder.addWedge(t, { width, height, depth }) + } + + if (i % 10000 === 0 && ctx.shouldUpdate) { + await ctx.update({ message: 'Polymer direction mesh', current: i, max: polymerElementCount }); + } + ++i + } + + return builder.getMesh() +} + +export const DefaultPolymerDirectionProps = { + ...DefaultMeshProps, + ...DefaultStructureProps, + sizeTheme: { name: 'physical', factor: 1 } as SizeTheme, + detail: 0, + unitKinds: [ Unit.Kind.Atomic, Unit.Kind.Spheres ] as Unit.Kind[] +} +export type PolymerDirectionProps = Partial<typeof DefaultPolymerDirectionProps> + +export function PolymerDirectionVisual(): UnitsVisual<PolymerDirectionProps> { + let renderObject: MeshRenderObject + let currentProps: typeof DefaultPolymerDirectionProps + let mesh: Mesh + let currentGroup: Unit.SymmetryGroup + + return { + get renderObject () { return renderObject }, + async create(ctx: RuntimeContext, group: Unit.SymmetryGroup, props: PolymerDirectionProps = {}) { + currentProps = Object.assign({}, DefaultPolymerDirectionProps, props) + currentGroup = group + + const { colorTheme, unitKinds } = { ...DefaultPolymerDirectionProps, ...props } + const instanceCount = group.units.length + const elementCount = group.elements.length + const unit = group.units[0] + + mesh = unitKinds.includes(unit.kind) + ? await createPolymerDirectionWedgeMesh(ctx, unit, mesh) + : Mesh.createEmpty(mesh) + + const transforms = createTransforms(group) + const color = createColors(group, elementCount, colorTheme) + const marker = createMarkers(instanceCount * elementCount) + + const counts = { drawCount: mesh.triangleCount * 3, elementCount, instanceCount } + + const values: MeshValues = { + ...getMeshData(mesh), + ...color, + ...marker, + aTransform: transforms, + elements: mesh.indexBuffer, + ...createMeshValues(currentProps, counts), + } + const state = createRenderableState(currentProps) + + renderObject = createMeshRenderObject(values, state) + }, + async update(ctx: RuntimeContext, props: PolymerDirectionProps) { + const newProps = Object.assign({}, currentProps, props) + + if (!renderObject) return false + + let updateColor = false + + if (newProps.detail !== currentProps.detail) { + const unit = currentGroup.units[0] + mesh = await createPolymerDirectionWedgeMesh(ctx, unit, mesh) + ValueCell.update(renderObject.values.drawCount, mesh.triangleCount * 3) + updateColor = true + } + + if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) { + updateColor = true + } + + if (updateColor) { + const elementCount = currentGroup.elements.length + if (ctx.shouldUpdate) await ctx.update('Computing direction colors'); + createColors(currentGroup, elementCount, newProps.colorTheme, renderObject.values) + } + + updateMeshValues(renderObject.values, newProps) + updateRenderableState(renderObject.state, newProps) + + currentProps = newProps + return true + }, + getLoci(pickingId: PickingId) { + const { objectId, instanceId, elementId } = pickingId + if (renderObject.id === objectId) { + const unit = currentGroup.units[instanceId] + const indices = OrderedSet.ofSingleton(elementId as StructureElement.UnitIndex); + return StructureElement.Loci([{ unit, indices }]) + } + return EmptyLoci + }, + mark(loci: Loci, action: MarkerAction) { + markElement(renderObject.values.tMarker, currentGroup, loci, action) + }, + destroy() { + // TODO + } + } +} diff --git a/src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts b/src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts index a32e1e64cf64dfeb9912894b8e61d03438098609..8d97c06f0de86a18d7f00b87c31afb35a78768ae 100644 --- a/src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts +++ b/src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts @@ -23,16 +23,10 @@ import { Loci, EmptyLoci } from 'mol-model/loci'; import { SizeTheme } from '../../../theme'; import { createMeshValues, updateMeshValues, updateRenderableState, createRenderableState, DefaultMeshProps } from '../../util'; import { MeshBuilder } from '../../../shape/mesh-builder'; -import { getPolymerElementCount, PolymerTraceIterator, interpolateNormals } from './util/polymer'; -import { Vec3, Mat4 } from 'mol-math/linear-algebra'; +import { getPolymerElementCount, PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment } from './util/polymer'; import { SecondaryStructureType, MoleculeType } from 'mol-model/structure/model/types'; // TODO handle polymer ends properly -// TODO avoid allocating Vec3, use global temp vars -// TODO move more interpolation code into ./util/polymer/interpolate -// TODO move direction wedges into separate visual - -const t = Mat4.identity() async function createPolymerTraceMesh(ctx: RuntimeContext, unit: Unit, mesh?: Mesh) { const polymerElementCount = getPolymerElementCount(unit) @@ -44,17 +38,8 @@ async function createPolymerTraceMesh(ctx: RuntimeContext, unit: Unit, mesh?: Me const linearSegments = 8 const radialSegments = 12 - const tanA = Vec3.zero() - const tanB = Vec3.zero() - - const tB = Vec3.zero() - const tangentVec = Vec3.zero() - - const pn = (linearSegments + 1) * 3 - const controlPoints = new Float32Array(pn) - const tangentVectors = new Float32Array(pn) - const normalVectors = new Float32Array(pn) - const binormalVectors = new Float32Array(pn) + const state = createCurveSegmentState(linearSegments) + const { curvePoints, normalVectors, binormalVectors } = state let i = 0 const polymerTraceIt = PolymerTraceIterator(unit) @@ -67,26 +52,8 @@ async function createPolymerTraceMesh(ctx: RuntimeContext, unit: Unit, mesh?: Me const isHelix = SecondaryStructureType.is(v.secStrucType, SecondaryStructureType.Flag.Helix) const tension = (isNucleic || isSheet) ? 0.5 : 0.9 - for (let j = 0; j <= linearSegments; ++j) { - const t = j * 1.0 / linearSegments; - // if ((v.last && t > 0.5) || (v.first && t < 0.5)) break - - if (t < 0.5) { - Vec3.spline(tB, v.t0, v.t1, v.t2, v.t3, t + 0.5, tension) - Vec3.spline(tanA, v.t0, v.t1, v.t2, v.t3, t + 0.5 + 0.01, tension) - Vec3.spline(tanB, v.t0, v.t1, v.t2, v.t3, t + 0.5 - 0.01, tension) - } else { - Vec3.spline(tB, v.t1, v.t2, v.t3, v.t4, t - 0.5, tension) - Vec3.spline(tanA, v.t1, v.t2, v.t3, v.t4, t - 0.5 + 0.01, tension) - Vec3.spline(tanB, v.t1, v.t2, v.t3, v.t4, t - 0.5 - 0.01, tension) - } - Vec3.toArray(tB, controlPoints, j * 3) - Vec3.normalize(tangentVec, Vec3.sub(tangentVec, tanA, tanB)) - Vec3.toArray(tangentVec, tangentVectors, j * 3) - } - // console.log('ELEMENT', i) - interpolateNormals(controlPoints, tangentVectors, normalVectors, binormalVectors, v.d12, v.d23) + interpolateCurveSegment(state, v, tension) let width = 0.2, height = 0.2 @@ -94,30 +61,14 @@ async function createPolymerTraceMesh(ctx: RuntimeContext, unit: Unit, mesh?: Me if (isSheet) { width = 0.15; height = 1.0 const arrowHeight = v.secStrucChange ? 1.7 : 0 - builder.addSheet(controlPoints, normalVectors, binormalVectors, linearSegments, width, height, arrowHeight, true, true) + builder.addSheet(curvePoints, normalVectors, binormalVectors, linearSegments, width, height, arrowHeight, true, true) } else { if (isHelix) { width = 0.2; height = 1.0 } else if (isNucleic) { width = 1.5; height = 0.3 } - builder.addTube(controlPoints, normalVectors, binormalVectors, linearSegments, radialSegments, width, height, 1, true, true) - } - - if ((isSheet && !v.secStrucChange) || !isSheet) { - const upVec = Vec3.zero() - let width = 0.5, height = 1.2, depth = 0.6 - if (isNucleic) { - Vec3.fromArray(upVec, binormalVectors, Math.round(linearSegments / 2) * 3) - depth = 0.9 - } else { - Vec3.fromArray(upVec, normalVectors, Math.round(linearSegments / 2) * 3) - } - - Mat4.targetTo(t, v.t3, v.t1, upVec) - Mat4.mul(t, t, Mat4.rotXY90) - Mat4.setTranslation(t, v.t2) - builder.addWedge(t, { width, height, depth }) + builder.addTube(curvePoints, normalVectors, binormalVectors, linearSegments, radialSegments, width, height, 1, true, true) } if (i % 10000 === 0 && ctx.shouldUpdate) { diff --git a/src/mol-geo/representation/structure/visual/util/polymer.ts b/src/mol-geo/representation/structure/visual/util/polymer.ts index 1054f7c32363ac2b3c5295044301e5d709e2943e..24d9b7e937e2953c1e1acb3c958a6f69de6b264c 100644 --- a/src/mol-geo/representation/structure/visual/util/polymer.ts +++ b/src/mol-geo/representation/structure/visual/util/polymer.ts @@ -11,7 +11,7 @@ import SortedRanges from 'mol-data/int/sorted-ranges'; export * from './polymer/backbone-iterator' export * from './polymer/gap-iterator' export * from './polymer/trace-iterator' -export * from './polymer/interpolate' +export * from './polymer/curve-segment' export function getPolymerRanges(unit: Unit): SortedRanges<ElementIndex> { switch (unit.kind) { diff --git a/src/mol-geo/representation/structure/visual/util/polymer/curve-segment.ts b/src/mol-geo/representation/structure/visual/util/polymer/curve-segment.ts new file mode 100644 index 0000000000000000000000000000000000000000..c5208d0527d59cd998a8659b06f9c0d05595a0bf --- /dev/null +++ b/src/mol-geo/representation/structure/visual/util/polymer/curve-segment.ts @@ -0,0 +1,118 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { Vec3 } from 'mol-math/linear-algebra'; + +export interface CurveSegmentState { + curvePoints: Helpers.NumberArray, + tangentVectors: Helpers.NumberArray, + normalVectors: Helpers.NumberArray, + binormalVectors: Helpers.NumberArray, + linearSegments: number +} + +export interface CurveSegmentControls { + p0: Vec3, p1: Vec3, p2: Vec3, p3: Vec3, p4: Vec3, + d12: Vec3, d23: Vec3 +} + +export function createCurveSegmentState(linearSegments: number): CurveSegmentState { + const pn = (linearSegments + 1) * 3 + return { + curvePoints: new Float32Array(pn), + tangentVectors: new Float32Array(pn), + normalVectors: new Float32Array(pn), + binormalVectors: new Float32Array(pn), + linearSegments + } +} + +export function interpolateCurveSegment(state: CurveSegmentState, controls: CurveSegmentControls, tension: number) { + interpolatePointsAndTangents(state, controls, tension) + interpolateNormals(state, controls) +} + +const tanA = Vec3.zero() +const tanB = Vec3.zero() +const tB = Vec3.zero() + +export function interpolatePointsAndTangents(state: CurveSegmentState, controls: CurveSegmentControls, tension: number) { + const { curvePoints, tangentVectors, linearSegments } = state + const { p0, p1, p2, p3, p4 } = controls + + for (let j = 0; j <= linearSegments; ++j) { + const t = j * 1.0 / linearSegments; + // if ((v.last && t > 0.5) || (v.first && t < 0.5)) break + + if (t < 0.5) { + Vec3.spline(tB, p0, p1, p2, p3, t + 0.5, tension) + Vec3.spline(tanA, p0, p1, p2, p3, t + 0.5 + 0.01, tension) + Vec3.spline(tanB, p0, p1, p2, p3, t + 0.5 - 0.01, tension) + } else { + Vec3.spline(tB, p1, p2, p3, p4, t - 0.5, tension) + Vec3.spline(tanA, p1, p2, p3, p4, t - 0.5 + 0.01, tension) + Vec3.spline(tanB, p1, p2, p3, p4, t - 0.5 - 0.01, tension) + } + Vec3.toArray(tB, curvePoints, j * 3) + Vec3.normalize(tangentVec, Vec3.sub(tangentVec, tanA, tanB)) + Vec3.toArray(tangentVec, tangentVectors, j * 3) + } +} + +const tmpNormal = Vec3.zero() +const tangentVec = Vec3.zero() +const normalVec = Vec3.zero() +const binormalVec = Vec3.zero() +const prevNormal = Vec3.zero() +const firstControlPoint = Vec3.zero() +const lastControlPoint = Vec3.zero() +const firstTangentVec = Vec3.zero() +const lastTangentVec = Vec3.zero() +const firstNormalVec = Vec3.zero() +const lastNormalVec = Vec3.zero() + +/** + * Populate normalVectors by interpolating from firstDirection to lastDirection with + * resulting vector perpendicular to tangentVectors and binormalVectors + */ +export function interpolateNormals(state: CurveSegmentState, controls: CurveSegmentControls) { + const { curvePoints, tangentVectors, normalVectors, binormalVectors } = state + const { d12: firstDirection, d23: lastDirection } = controls + + const n = curvePoints.length / 3 + + Vec3.fromArray(firstControlPoint, curvePoints, 0) + Vec3.fromArray(lastControlPoint, curvePoints, (n - 1) * 3) + Vec3.fromArray(firstTangentVec, tangentVectors, 0) + Vec3.fromArray(lastTangentVec, tangentVectors, (n - 1) * 3) + + Vec3.normalize(tmpNormal, Vec3.sub(tmpNormal, firstControlPoint, firstDirection)) + Vec3.orthogonalize(firstNormalVec, firstTangentVec, tmpNormal) + + Vec3.normalize(tmpNormal, Vec3.sub(tmpNormal, lastControlPoint, lastDirection)) + Vec3.orthogonalize(lastNormalVec, lastTangentVec, tmpNormal) + + if (Vec3.dot(firstNormalVec, lastNormalVec) < 0) { + Vec3.scale(lastNormalVec, lastNormalVec, -1) + } + + Vec3.copy(prevNormal, firstNormalVec) + + for (let i = 0; i < n; ++i) { + const t = i === 0 ? 0 : 1 / (n - i) + Vec3.normalize(tmpNormal, Vec3.slerp(tmpNormal, prevNormal, lastNormalVec, t)) + + Vec3.fromArray(tangentVec, tangentVectors, i * 3) + + Vec3.orthogonalize(normalVec, tangentVec, tmpNormal) + Vec3.toArray(normalVec, normalVectors, i * 3) + + Vec3.copy(prevNormal, normalVec) + + Vec3.normalize(binormalVec, Vec3.cross(binormalVec, tangentVec, normalVec)) + Vec3.toArray(binormalVec, binormalVectors, i * 3) + } +} \ No newline at end of file diff --git a/src/mol-geo/representation/structure/visual/util/polymer/interpolate.ts b/src/mol-geo/representation/structure/visual/util/polymer/interpolate.ts deleted file mode 100644 index 1bf139858e6a841e71df2d72bf86628003e86f8d..0000000000000000000000000000000000000000 --- a/src/mol-geo/representation/structure/visual/util/polymer/interpolate.ts +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - */ - -import { Vec3 } from 'mol-math/linear-algebra'; - -const tmpNormal = Vec3.zero() -const tangentVec = Vec3.zero() -const normalVec = Vec3.zero() -const binormalVec = Vec3.zero() -const prevNormal = Vec3.zero() -const firstControlPoint = Vec3.zero() -const lastControlPoint = Vec3.zero() -const firstTangentVec = Vec3.zero() -const lastTangentVec = Vec3.zero() -const firstNormalVec = Vec3.zero() -const lastNormalVec = Vec3.zero() - -/** - * Populate normalVectors by interpolating from firstDirection to lastDirection with - * resulting vector perpendicular to tangentVectors and binormalVectors - */ -export function interpolateNormals(controlPoints: Helpers.NumberArray, tangentVectors: Helpers.NumberArray, normalVectors: Helpers.NumberArray, binormalVectors: Helpers.NumberArray, firstDirection: Vec3, lastDirection: Vec3) { - const n = controlPoints.length / 3 - - Vec3.fromArray(firstControlPoint, controlPoints, 0) - Vec3.fromArray(lastControlPoint, controlPoints, (n - 1) * 3) - Vec3.fromArray(firstTangentVec, tangentVectors, 0) - Vec3.fromArray(lastTangentVec, tangentVectors, (n - 1) * 3) - - Vec3.normalize(tmpNormal, Vec3.sub(tmpNormal, firstControlPoint, firstDirection)) - Vec3.orthogonalize(firstNormalVec, firstTangentVec, tmpNormal) - - Vec3.normalize(tmpNormal, Vec3.sub(tmpNormal, lastControlPoint, lastDirection)) - Vec3.orthogonalize(lastNormalVec, lastTangentVec, tmpNormal) - - if (Vec3.dot(firstNormalVec, lastNormalVec) < 0) { - Vec3.scale(lastNormalVec, lastNormalVec, -1) - } - - Vec3.copy(prevNormal, firstNormalVec) - - for (let i = 0; i < n; ++i) { - const t = i === 0 ? 0 : 1 / (n - i) - Vec3.normalize(tmpNormal, Vec3.slerp(tmpNormal, prevNormal, lastNormalVec, t)) - - Vec3.fromArray(tangentVec, tangentVectors, i * 3) - - Vec3.orthogonalize(normalVec, tangentVec, tmpNormal) - Vec3.toArray(normalVec, normalVectors, i * 3) - - Vec3.copy(prevNormal, normalVec) - - Vec3.normalize(binormalVec, Vec3.cross(binormalVec, tangentVec, normalVec)) - Vec3.toArray(binormalVec, binormalVectors, i * 3) - } -} \ No newline at end of file diff --git a/src/mol-geo/representation/structure/visual/util/polymer/trace-iterator.ts b/src/mol-geo/representation/structure/visual/util/polymer/trace-iterator.ts index 363981362c4b190cfd181888dd843416eee44654..e304208088159359912777b228740c80288d120c 100644 --- a/src/mol-geo/representation/structure/visual/util/polymer/trace-iterator.ts +++ b/src/mol-geo/representation/structure/visual/util/polymer/trace-iterator.ts @@ -33,7 +33,8 @@ interface PolymerTraceElement { secStrucType: SecondaryStructureType secStrucChange: boolean moleculeType: MoleculeType - t0: Vec3, t1: Vec3, t2: Vec3, t3: Vec3, t4: Vec3 + + p0: Vec3, p1: Vec3, p2: Vec3, p3: Vec3, p4: Vec3 d12: Vec3, d23: Vec3 } @@ -44,7 +45,7 @@ function createPolymerTraceElement (unit: Unit): PolymerTraceElement { secStrucType: SecondaryStructureType.create(SecondaryStructureType.Flag.NA), secStrucChange: false, moleculeType: MoleculeType.unknown, - t0: Vec3.zero(), t1: Vec3.zero(), t2: Vec3.zero(), t3: Vec3.zero(), t4: Vec3.zero(), + p0: Vec3.zero(), p1: Vec3.zero(), p2: Vec3.zero(), p3: Vec3.zero(), p4: Vec3.zero(), d12: Vec3.create(1, 0, 0), d23: Vec3.create(1, 0, 0), } } @@ -162,11 +163,11 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement> this.value.secStrucType = this.unit.model.properties.secondaryStructure.type[residueIndex] - this.setControlPoint(value.t0, this.p0, this.p1, this.p2, residueIndex - 2 as ResidueIndex) - this.setControlPoint(value.t1, this.p1, this.p2, this.p3, residueIndex - 1 as ResidueIndex) - this.setControlPoint(value.t2, this.p2, this.p3, this.p4, residueIndex) - this.setControlPoint(value.t3, this.p3, this.p4, this.p5, residueIndex + 1 as ResidueIndex) - this.setControlPoint(value.t4, this.p4, this.p5, this.p6, residueIndex + 2 as ResidueIndex) + this.setControlPoint(value.p0, this.p0, this.p1, this.p2, residueIndex - 2 as ResidueIndex) + this.setControlPoint(value.p1, this.p1, this.p2, this.p3, residueIndex - 1 as ResidueIndex) + this.setControlPoint(value.p2, this.p2, this.p3, this.p4, residueIndex) + this.setControlPoint(value.p3, this.p3, this.p4, this.p5, residueIndex + 1 as ResidueIndex) + this.setControlPoint(value.p4, this.p4, this.p5, this.p6, residueIndex + 2 as ResidueIndex) Vec3.copy(value.d12, this.v12) Vec3.copy(value.d23, this.v23) @@ -231,11 +232,11 @@ export class CoarsePolymerTraceIterator implements Iterator<PolymerTraceElement> this.elementIndex += 1 this.value.center.element = this.value.center.unit.elements[this.elementIndex] - this.pos(this.value.t0, this.elementIndex - 2) - this.pos(this.value.t1, this.elementIndex - 1) - this.pos(this.value.t2, this.elementIndex) - this.pos(this.value.t3, this.elementIndex + 1) - this.pos(this.value.t4, this.elementIndex + 2) + this.pos(this.value.p0, this.elementIndex - 2) + this.pos(this.value.p1, this.elementIndex - 1) + this.pos(this.value.p2, this.elementIndex) + this.pos(this.value.p3, this.elementIndex + 1) + this.pos(this.value.p4, this.elementIndex + 2) this.value.first = this.elementIndex === this.polymerSegment.start this.value.last = this.elementIndex === this.polymerSegment.end - 1 diff --git a/src/mol-view/stage.ts b/src/mol-view/stage.ts index 992773ebbcb7ebabebc69f38c9621482cd026112..1fc6ce73a9455caa7e57163f148da127e53dba7c 100644 --- a/src/mol-view/stage.ts +++ b/src/mol-view/stage.ts @@ -72,6 +72,7 @@ export class Stage { this.ctx.viewer = this.viewer // this.loadPdbid('1jj2') + // this.loadPdbid('1grm') // helix-like sheets // this.loadPdbid('4umt') // ligand has bond with order 3 // this.loadPdbid('1crn') // small // this.loadPdbid('1hrv') // viral assembly