Skip to content
Snippets Groups Projects
Commit 8fed9a45 authored by Alexander Rose's avatar Alexander Rose
Browse files

basic support for interpolated size of tube polymer traces

parent be47988c
No related branches found
No related tags found
No related merge requests found
......@@ -27,7 +27,7 @@ function add3AndScale2(out: Vec3, a: Vec3, b: Vec3, c: Vec3, sa: number, sb: num
out[2] = (a[2] * sa) + (b[2] * sb) + c[2];
}
export function addTube(state: MeshBuilder.State, controlPoints: ArrayLike<number>, normalVectors: ArrayLike<number>, binormalVectors: ArrayLike<number>, linearSegments: number, radialSegments: number, width: number, height: number, waveFactor: number, startCap: boolean, endCap: boolean) {
export function addTube(state: MeshBuilder.State, controlPoints: ArrayLike<number>, normalVectors: ArrayLike<number>, binormalVectors: ArrayLike<number>, linearSegments: number, radialSegments: number, widthValues: ArrayLike<number>, heightValues: ArrayLike<number>, waveFactor: number, startCap: boolean, endCap: boolean) {
const { currentGroup, vertices, normals, indices, groups } = state
let vertexCount = vertices.elementCount
......@@ -39,6 +39,9 @@ export function addTube(state: MeshBuilder.State, controlPoints: ArrayLike<numbe
Vec3.fromArray(v, binormalVectors, i3)
Vec3.fromArray(controlPoint, controlPoints, i3)
const width = widthValues[i]
const height = heightValues[i]
const tt = di * i - 0.5;
const ff = 1 + (waveFactor - 1) * (Math.cos(2 * Math.PI * tt) + 1);
const w = ff * width, h = ff * height;
......@@ -83,6 +86,9 @@ export function addTube(state: MeshBuilder.State, controlPoints: ArrayLike<numbe
ChunkedArray.add3(vertices, controlPoint[0], controlPoint[1], controlPoint[2]);
ChunkedArray.add3(normals, normalVector[0], normalVector[1], normalVector[2]);
const width = widthValues[0]
const height = heightValues[0]
vertexCount = vertices.elementCount
for (let i = 0; i < radialSegments; ++i) {
const t = 2 * Math.PI * i / radialSegments;
......@@ -112,6 +118,9 @@ export function addTube(state: MeshBuilder.State, controlPoints: ArrayLike<numbe
ChunkedArray.add3(vertices, controlPoint[0], controlPoint[1], controlPoint[2]);
ChunkedArray.add3(normals, normalVector[0], normalVector[1], normalVector[2]);
const width = widthValues[linearSegments]
const height = heightValues[linearSegments]
vertexCount = vertices.elementCount
for (let i = 0; i < radialSegments; ++i) {
const t = 2 * Math.PI * i / radialSegments
......
......@@ -7,7 +7,7 @@
import { Unit, Structure } from 'mol-model/structure';
import { UnitsVisual } from '../representation';
import { VisualUpdateState } from '../../util';
import { PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment, PolymerLocationIterator, getPolymerElementLoci, markPolymerElement } from './util/polymer';
import { PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment, PolymerLocationIterator, getPolymerElementLoci, markPolymerElement, interpolateSizes } from './util/polymer';
import { SecondaryStructureType, isNucleic } from 'mol-model/structure/model/types';
import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual';
import { ParamDefinition as PD } from 'mol-util/param-definition';
......@@ -41,7 +41,7 @@ function createPolymerTraceMesh(ctx: VisualContext, unit: Unit, structure: Struc
const isCoarse = Unit.isCoarse(unit)
const state = createCurveSegmentState(linearSegments)
const { curvePoints, normalVectors, binormalVectors } = state
const { curvePoints, normalVectors, binormalVectors, widthValues, heightValues } = state
let i = 0
const polymerTraceIt = PolymerTraceIterator(unit)
......@@ -57,24 +57,39 @@ function createPolymerTraceMesh(ctx: VisualContext, unit: Unit, structure: Struc
interpolateCurveSegment(state, v, tension, shift)
let width = theme.size.size(v.center) * sizeFactor
if (isCoarse) width *= aspectRatio / 2
let w0 = theme.size.size(v.centerPrev) * sizeFactor
let w1 = theme.size.size(v.center) * sizeFactor
let w2 = theme.size.size(v.centerNext) * sizeFactor
if (isCoarse) {
w0 *= aspectRatio / 2
w1 *= aspectRatio / 2
w2 *= aspectRatio / 2
}
if (isSheet) {
const height = width * aspectRatio
const arrowHeight = v.secStrucLast ? height * arrowFactor : 0
addSheet(builderState, curvePoints, normalVectors, binormalVectors, linearSegments, width, height, arrowHeight, v.secStrucFirst, v.secStrucLast)
const h1 = w1 * aspectRatio
const arrowHeight = v.secStrucLast ? h1 * arrowFactor : 0
addSheet(builderState, curvePoints, normalVectors, binormalVectors, linearSegments, w1, h1, arrowHeight, v.secStrucFirst, v.secStrucLast)
} else {
let height: number
let h0: number, h1: number, h2: number
if (isHelix) {
height = width * aspectRatio
h0 = w0 * aspectRatio
h1 = w1 * aspectRatio
h2 = w2 * aspectRatio
} else if (isNucleicType) {
height = width * aspectRatio;
[width, height] = [height, width]
h0 = w0 * aspectRatio;
[w0, h0] = [h0, w0]
h1 = w1 * aspectRatio;
[w1, h1] = [h1, w1]
h2 = w2 * aspectRatio;
[w2, h2] = [h2, w2]
} else {
height = width
h0 = w0
h1 = w1
h2 = w2
}
addTube(builderState, curvePoints, normalVectors, binormalVectors, linearSegments, radialSegments, width, height, 1, v.secStrucFirst, v.secStrucLast)
interpolateSizes(state, w0, w1, w2, h0, h1, h2, shift)
addTube(builderState, curvePoints, normalVectors, binormalVectors, linearSegments, radialSegments, widthValues, heightValues, 1, v.secStrucFirst, v.secStrucLast)
}
++i
......
......@@ -6,12 +6,15 @@
import { Vec3 } from 'mol-math/linear-algebra';
import { NumberArray } from 'mol-util/type-helpers';
import { lerp } from 'mol-math/interpolate';
export interface CurveSegmentState {
curvePoints: NumberArray,
tangentVectors: NumberArray,
normalVectors: NumberArray,
binormalVectors: NumberArray,
widthValues: NumberArray,
heightValues: NumberArray,
linearSegments: number
}
......@@ -21,12 +24,15 @@ export interface CurveSegmentControls {
}
export function createCurveSegmentState(linearSegments: number): CurveSegmentState {
const pn = (linearSegments + 1) * 3
const n = linearSegments + 1
const pn = n * 3
return {
curvePoints: new Float32Array(pn),
tangentVectors: new Float32Array(pn),
normalVectors: new Float32Array(pn),
binormalVectors: new Float32Array(pn),
widthValues: new Float32Array(n),
heightValues: new Float32Array(n),
linearSegments
}
}
......@@ -112,4 +118,21 @@ export function interpolateNormals(state: CurveSegmentState, controls: CurveSegm
Vec3.normalize(binormalVec, Vec3.cross(binormalVec, tangentVec, normalVec))
Vec3.toArray(binormalVec, binormalVectors, i * 3)
}
}
export function interpolateSizes(state: CurveSegmentState, w0: number, w1: number, w2: number, h0: number, h1: number, h2: number, shift: number) {
const { widthValues, heightValues, linearSegments } = state
const shift1 = 1 - shift
for (let i = 0; i <= linearSegments; ++i) {
const t = i * 1.0 / linearSegments;
if (t < shift1) {
widthValues[i] = lerp(w0, w1, t + shift)
heightValues[i] = lerp(h0, h1, t + shift)
} else {
widthValues[i] = lerp(w1, w2, t - shift1)
heightValues[i] = lerp(h1, h2, t - shift1)
}
}
}
\ No newline at end of file
......@@ -29,6 +29,8 @@ export function PolymerTraceIterator(unit: Unit): Iterator<PolymerTraceElement>
interface PolymerTraceElement {
center: StructureElement
centerPrev: StructureElement
centerNext: StructureElement
first: boolean, last: boolean
secStrucFirst: boolean, secStrucLast: boolean
secStrucType: SecondaryStructureType
......@@ -43,6 +45,8 @@ const SecStrucTypeNA = SecondaryStructureType.create(SecondaryStructureType.Flag
function createPolymerTraceElement (unit: Unit): PolymerTraceElement {
return {
center: StructureElement.create(unit),
centerPrev: StructureElement.create(unit),
centerNext: StructureElement.create(unit),
first: false, last: false,
secStrucFirst: false, secStrucLast: false,
secStrucType: SecStrucTypeNA,
......@@ -154,23 +158,35 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement>
this.nextSecStrucType = residueIt.hasNext ? this.secondaryStructureType[residueIndex + 1] : SecStrucTypeNA
value.secStrucType = this.currSecStrucType
value.center.element = this.traceElementIndex[residueIndex]
value.first = residueIndex === this.residueSegmentMin
value.last = residueIndex === this.residueSegmentMax
value.secStrucFirst = this.prevSecStrucType !== this.currSecStrucType
value.secStrucLast = this.currSecStrucType !== this.nextSecStrucType
value.moleculeType = this.moleculeType[residueIndex]
const residueIndexPrev3 = this.getResidueIndex(residueIndex - 3)
const residueIndexPrev2 = this.getResidueIndex(residueIndex - 2)
const residueIndexPrev1 = this.getResidueIndex(residueIndex - 1)
const residueIndexNext1 = this.getResidueIndex(residueIndex + 1)
const residueIndexNext2 = this.getResidueIndex(residueIndex + 2)
const residueIndexNext3 = this.getResidueIndex(residueIndex + 3)
if (value.first) {
this.pos(this.p0, this.traceElementIndex[this.getResidueIndex(residueIndex - 3)])
this.pos(this.p1, this.traceElementIndex[this.getResidueIndex(residueIndex - 2)])
this.pos(this.p2, this.traceElementIndex[this.getResidueIndex(residueIndex - 1)])
this.pos(this.p3, value.center.element)
this.pos(this.p4, this.traceElementIndex[this.getResidueIndex(residueIndex + 1)])
this.pos(this.p5, this.traceElementIndex[this.getResidueIndex(residueIndex + 2)])
this.pos(this.v12, this.directionElementIndex[this.getResidueIndex(residueIndex - 1)])
value.centerPrev.element = this.traceElementIndex[residueIndexPrev1]
value.center.element = this.traceElementIndex[residueIndex]
this.pos(this.p0, this.traceElementIndex[residueIndexPrev3])
this.pos(this.p1, this.traceElementIndex[residueIndexPrev2])
this.pos(this.p2, this.traceElementIndex[residueIndexPrev1])
this.pos(this.p3, this.traceElementIndex[residueIndex])
this.pos(this.p4, this.traceElementIndex[residueIndexNext1])
this.pos(this.p5, this.traceElementIndex[residueIndexNext2])
this.pos(this.v12, this.directionElementIndex[residueIndexPrev1])
} else {
value.centerPrev.element = value.center.element
value.center.element = value.centerNext.element
Vec3.copy(this.p0, this.p1)
Vec3.copy(this.p1, this.p2)
Vec3.copy(this.p2, this.p3)
......@@ -180,14 +196,15 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement>
Vec3.copy(this.v12, this.v23)
}
this.pos(this.p6, this.traceElementIndex[this.getResidueIndex(residueIndex + 3 as ResidueIndex)])
value.centerNext.element = this.traceElementIndex[residueIndexNext1]
this.pos(this.p6, this.traceElementIndex[residueIndexNext3])
this.pos(this.v23, this.directionElementIndex[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.p0, this.p0, this.p1, this.p2, residueIndexPrev2)
this.setControlPoint(value.p1, this.p1, this.p2, this.p3, residueIndexPrev1)
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)
this.setControlPoint(value.p3, this.p3, this.p4, this.p5, residueIndexNext1)
this.setControlPoint(value.p4, this.p4, this.p5, this.p6, residueIndexNext2)
Vec3.copy(value.d12, this.v12)
Vec3.copy(value.d23, this.v23)
......@@ -228,8 +245,11 @@ export class CoarsePolymerTraceIterator implements Iterator<PolymerTraceElement>
private elementIndex: number
hasNext: boolean = false;
private getElementIndex(elementIndex: number) {
return Math.min(Math.max(this.polymerSegment.start, elementIndex), this.polymerSegment.end - 1) as ElementIndex
}
private pos(target: Vec3, elementIndex: number) {
elementIndex = Math.min(Math.max(this.polymerSegment.start, elementIndex), this.polymerSegment.end - 1)
const index = this.unit.elements[elementIndex]
target[0] = this.conformation.x[index]
target[1] = this.conformation.y[index]
......@@ -251,13 +271,21 @@ export class CoarsePolymerTraceIterator implements Iterator<PolymerTraceElement>
if (this.state === CoarsePolymerTraceIteratorState.nextElement) {
this.elementIndex += 1
const elementIndexPrev2 = this.getElementIndex(this.elementIndex - 2)
const elementIndexPrev1 = this.getElementIndex(this.elementIndex - 1)
const elementIndexNext1 = this.getElementIndex(this.elementIndex + 1)
const elementIndexNext2 = this.getElementIndex(this.elementIndex + 2)
this.value.centerPrev.element = this.value.center.unit.elements[elementIndexPrev1]
this.value.center.element = this.value.center.unit.elements[this.elementIndex]
this.value.centerNext.element = this.value.center.unit.elements[elementIndexNext1]
this.pos(this.value.p0, this.elementIndex - 2)
this.pos(this.value.p1, this.elementIndex - 1)
this.pos(this.value.p0, elementIndexPrev2)
this.pos(this.value.p1, elementIndexPrev1)
this.pos(this.value.p2, this.elementIndex)
this.pos(this.value.p3, this.elementIndex + 1)
this.pos(this.value.p4, this.elementIndex + 2)
this.pos(this.value.p3, elementIndexNext1)
this.pos(this.value.p4, elementIndexNext2)
this.value.first = this.elementIndex === this.polymerSegment.start
this.value.last = this.elementIndex === this.polymerSegment.end - 1
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment