diff --git a/src/mol-data/int/impl/segmentation.ts b/src/mol-data/int/impl/segmentation.ts index f3e7413f97c11d597eae86d519285c418c28671d..99e7114cb7b6419c830a3c0c2acbbd4bac6c3907 100644 --- a/src/mol-data/int/impl/segmentation.ts +++ b/src/mol-data/int/impl/segmentation.ts @@ -52,18 +52,22 @@ export function projectValue({ segments }: Segmentation, set: OrderedSet, value: } export class SegmentIterator<T extends number = number> implements Iterator<Segs.Segment<T>> { - private segmentMin = 0; - private segmentMax = 0; + private _segmentMin = 0; + private _segmentMax = 0; + private segmentCur = 0; private setRange = Interval.Empty; private value: Segs.Segment<T> = { index: 0, start: 0 as T, end: 0 as T }; hasNext: boolean = false; + get segmentMin() { return this._segmentMin } + get segmentMax() { return this._segmentMax } + move() { while (this.hasNext) { if (this.updateValue()) { - this.value.index = this.segmentMin++; - this.hasNext = this.segmentMax >= this.segmentMin && Interval.size(this.setRange) > 0; + this.value.index = this.segmentCur++; + this.hasNext = this._segmentMax >= this.segmentCur && Interval.size(this.setRange) > 0; break; } else { this.updateSegmentRange(); @@ -73,7 +77,7 @@ export class SegmentIterator<T extends number = number> implements Iterator<Segs } private updateValue() { - const segmentEnd = this.segments[this.segmentMin + 1]; + const segmentEnd = this.segments[this.segmentCur + 1]; // TODO: add optimized version for interval and array? const setEnd = OrderedSet.findPredecessorIndexInInterval(this.set, segmentEnd, this.setRange); this.value.start = Interval.start(this.setRange) as T; @@ -89,10 +93,11 @@ export class SegmentIterator<T extends number = number> implements Iterator<Segs return; } - this.segmentMin = this.segmentMap[OrderedSet.getAt(this.set, sMin)]; - this.segmentMax = this.segmentMap[OrderedSet.getAt(this.set, sMax)]; + this.segmentCur = this.segmentMap[OrderedSet.getAt(this.set, sMin)]; + this._segmentMax = this.segmentMap[OrderedSet.getAt(this.set, sMax)]; - this.hasNext = this.segmentMax >= this.segmentMin; + this._segmentMin = this.segmentCur + this.hasNext = this._segmentMax >= this.segmentCur; } setSegment(segment: Segs.Segment<T>) { 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 f0bfe33559d7fbaaca324f441706e32d4e9614c0..1866005b5125027c6bc3dbc8ccead530164dd60b 100644 --- a/src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts +++ b/src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts @@ -26,17 +26,11 @@ import { MeshBuilder } from '../../../shape/mesh-builder'; import { getPolymerElementCount, PolymerTraceIterator } from './util/polymer'; import { Vec3 } from 'mol-math/linear-algebra'; -// export function spline(target: THREE.Vector3, p1: THREE.Vector3, p2: THREE.Vector3, p3: THREE.Vector3, t: number) { -// let a = Math.pow(1 - t, 2) / 2; -// let c = Math.pow(t, 2) / 2; -// let b = 1 - a - c; - -// let x = a * p1.x + b * p2.x + c * p3.x; -// let y = a * p1.y + b * p2.y + c * p3.y; -// let z = a * p1.z + b * p2.z + c * p3.z; - -// target.set(x, y, z); -// } +export function reflect(target: Vec3, p1: Vec3, p2: Vec3, amount: number) { + target[0] = p1[0] - amount * (p2[0] - p1[0]) + target[1] = p1[1] - amount * (p2[1] - p1[1]) + target[2] = p1[2] - amount * (p2[2] - p1[2]) +} async function createPolymerTraceMesh(ctx: RuntimeContext, unit: Unit, mesh?: Mesh) { const polymerElementCount = getPolymerElementCount(unit) @@ -45,34 +39,150 @@ async function createPolymerTraceMesh(ctx: RuntimeContext, unit: Unit, mesh?: Me // TODO better vertex count estimates const builder = MeshBuilder.create(polymerElementCount * 30, polymerElementCount * 30 / 2, mesh) - const linearSegmentCount = 10 + const linearSegments = 5 + const radialSegments = 8 + const tension = 0.9 + + const tA = Vec3.zero() + const tB = Vec3.zero() + const dA = Vec3.zero() + const dB = Vec3.zero() + const torsionVec = Vec3.zero() + const initialTorsionVec = Vec3.zero() + const tangentVec = Vec3.zero() + const normalVec = Vec3.zero() - const v0 = Vec3.zero() - const v1 = Vec3.zero() + const tmp = Vec3.zero() + const reflectedControlPoint = Vec3.zero() + + const pn = (linearSegments + 1) * 3 + const controlPoints = new Float32Array(pn) + const torsionVectors = new Float32Array(pn) + const normalVectors = new Float32Array(pn) let i = 0 const polymerTraceIt = PolymerTraceIterator(unit) while (polymerTraceIt.hasNext) { const v = polymerTraceIt.move() + builder.setId(v.index) - Vec3.spline(v1, v.c0, v.c1, v.c2, v.c3, 0.5, 0.5) + Vec3.spline(tB, v.t1, v.t2, v.t3, v.t4, 0.5, tension) + Vec3.spline(dA, v.d12, v.d23, v.d34, v.d45, 0.5, tension) - builder.setId(v.index) - for (let j = 1; j <= linearSegmentCount; ++j) { - let t = j * 1.0 / linearSegmentCount; - Vec3.copy(v0, v1) + Vec3.normalize(initialTorsionVec, Vec3.sub(initialTorsionVec, tB, dB)) + + Vec3.toArray(tB, controlPoints, 0) + Vec3.normalize(torsionVec, Vec3.sub(torsionVec, tB, dB)) + Vec3.toArray(torsionVec, torsionVectors, 0) + // approximate tangent as direction to previous control point + Vec3.normalize(tangentVec, Vec3.sub(tangentVec, tB, tA)) + Vec3.normalize(normalVec, Vec3.cross(normalVec, tangentVec, torsionVec)) + Vec3.toArray(normalVec, normalVectors, 0) + + // + + const t12 = Vec3.zero() + const t23 = Vec3.zero() + const t34 = Vec3.zero() + const t45 = Vec3.zero() + Vec3.spline(t12, v.t0, v.t1, v.t2, v.t3, 0.5, tension) + Vec3.spline(t23, v.t1, v.t2, v.t3, v.t4, 0.5, tension) + Vec3.spline(t34, v.t2, v.t3, v.t4, v.t5, 0.5, tension) + Vec3.spline(t45, v.t3, v.t4, v.t5, v.t6, 0.5, tension) + + // const dp12 = Vec3.zero() + // const dp23 = Vec3.zero() + // const dp34 = Vec3.zero() + // const dp45 = Vec3.zero() + // Vec3.projectPointOnVector(dp12, v.d12, t12, v.t1) + // Vec3.projectPointOnVector(dp23, v.d23, t23, v.t2) + // Vec3.projectPointOnVector(dp34, v.d34, t34, v.t3) + // Vec3.projectPointOnVector(dp45, v.d45, t45, v.t4) + + const td12 = Vec3.zero() + const td23 = Vec3.zero() + const td34 = Vec3.zero() + const td45 = Vec3.zero() + Vec3.normalize(td12, Vec3.sub(td12, t12, v.d12)) + Vec3.scaleAndAdd(v.d12, t12, td12, 1) + Vec3.normalize(td23, Vec3.sub(td23, t23, v.d23)) + if (Vec3.dot(td12, td23) < 0) { + Vec3.scaleAndAdd(v.d23, t23, td23, -1) + console.log('foo td0 td1') + } else { + Vec3.scaleAndAdd(v.d23, t23, td23, 1) + } + Vec3.normalize(td34, Vec3.sub(td34, t34, v.d34)) + if (Vec3.dot(td12, td34) < 0) { + Vec3.scaleAndAdd(v.d34, t34, td34, -1) + console.log('foo td1 td2') + } else { + Vec3.scaleAndAdd(v.d34, t34, td34, 1) + } + Vec3.normalize(td45, Vec3.sub(td45, t45, v.d45)) + if (Vec3.dot(td12, td45) < 0) { + Vec3.scaleAndAdd(v.d45, t45, td45, -1) + console.log('foo td2 td3') + } else { + Vec3.scaleAndAdd(v.d45, t45, td45, 1) + } + + // console.log(td0, td1, td2, td3) + + builder.addIcosahedron(t12, 0.3, 1) + builder.addIcosahedron(t23, 0.3, 1) + builder.addIcosahedron(t34, 0.3, 1) + builder.addIcosahedron(t45, 0.3, 1) + + // builder.addIcosahedron(dp12, 0.3, 1) + // builder.addIcosahedron(dp23, 0.3, 1) + // builder.addIcosahedron(dp34, 0.3, 1) + // builder.addIcosahedron(dp45, 0.3, 1) + + builder.addIcosahedron(v.d12, 0.3, 1) + builder.addIcosahedron(v.d23, 0.3, 1) + builder.addIcosahedron(v.d34, 0.3, 1) + builder.addIcosahedron(v.d45, 0.3, 1) + + for (let j = 1; j <= linearSegments; ++j) { + const t = j * 1.0 / linearSegments; + Vec3.copy(tA, tB) // if ((v.last && t > 0.5) || (v.first && t < 0.5)) break + if (t < 0.5) { - Vec3.spline(v1, v.c0, v.c1, v.c2, v.c3, t + 0.5, 0.5) + Vec3.spline(tB, v.t1, v.t2, v.t3, v.t4, t + 0.5, tension) } else { - Vec3.spline(v1, v.c1, v.c2, v.c3, v.c4, t - 0.5, 0.5) + Vec3.spline(tB, v.t2, v.t3, v.t4, v.t5, t - 0.5, tension) } + Vec3.spline(dB, v.d12, v.d23, v.d34, v.d45, t, tension) + + // reflect(reflectedControlPoint, tB, tA, 1) + Vec3.toArray(tB, controlPoints, j * 3) + + Vec3.normalize(torsionVec, Vec3.sub(torsionVec, tB, dB)) + // if (Vec3.dot(initialTorsionVec, torsionVec) < 0) Vec3.scale(torsionVec, torsionVec, -1) + Vec3.toArray(torsionVec, torsionVectors, j * 3) + + // approximate tangent as direction to previous control point + Vec3.normalize(tangentVec, Vec3.sub(tangentVec, tB, tA)) + Vec3.normalize(normalVec, Vec3.cross(normalVec, tangentVec, torsionVec)) + Vec3.toArray(normalVec, normalVectors, j * 3) + // TODO size theme - builder.addCylinder(v0, v1, 1.0, { radiusTop: 0.1, radiusBottom: 0.1 }) + // builder.addCylinder(tA, tB, 1.0, { radiusTop: 0.3, radiusBottom: 0.3 }) + + builder.addIcosahedron(dB, 0.1, 1) + + builder.addCylinder(tB, Vec3.add(tmp, tB, torsionVec), 1.0, { radiusTop: 0.1, radiusBottom: 0.1 }) + // builder.addCylinder(tB, Vec3.add(tmp, tB, normalVec), 1.0, { radiusTop: 0.1, radiusBottom: 0.1 }) + + console.log(tA, tB) } + builder.addTube(controlPoints, torsionVectors, normalVectors, linearSegments, radialSegments) + if (i % 10000 === 0 && ctx.shouldUpdate) { - await ctx.update({ message: 'Backbone mesh', current: i, max: polymerElementCount }); + await ctx.update({ message: 'Polymer trace mesh', current: i, max: polymerElementCount }); } ++i } diff --git a/src/mol-geo/representation/structure/visual/util/polymer.ts b/src/mol-geo/representation/structure/visual/util/polymer.ts index 0381dc63b08bdefc3c028b2be77049423d05cf18..0141f8b5b4511e0fee8c37e53da1a313f4a11061 100644 --- a/src/mol-geo/representation/structure/visual/util/polymer.ts +++ b/src/mol-geo/representation/structure/visual/util/polymer.ts @@ -5,7 +5,7 @@ */ import { Unit, Element, StructureProperties, Model } from 'mol-model/structure'; -import { Segmentation } from 'mol-data/int'; +import { Segmentation, Interval } from 'mol-data/int'; import { MoleculeType } from 'mol-model/structure/model/types'; import Iterator from 'mol-data/iterator'; import { SegmentIterator } from 'mol-data/int/impl/segmentation'; @@ -83,8 +83,12 @@ function getTraceName2(model: Model, residueModelIndex: number) { let traceName = '' if (moleculeType === MoleculeType.protein) { traceName = 'CA' - } else if (moleculeType === MoleculeType.DNA || moleculeType === MoleculeType.RNA) { - traceName = 'P' + } else if (moleculeType === MoleculeType.DNA) { + // traceName = 'P' + traceName = 'C3\'' + } else if (moleculeType === MoleculeType.RNA) { + // traceName = 'P' + traceName = 'C4\'' } return traceName } @@ -99,6 +103,32 @@ function getTraceElement2(model: Model, residueModelSegment: Segmentation.Segmen return residueModelSegment.start } +function getDirectionName2(model: Model, residueModelIndex: number) { + const compId = model.atomicHierarchy.residues.label_comp_id.value(residueModelIndex) + const chemCompMap = model.properties.chemicalComponentMap + const cc = chemCompMap.get(compId) + const moleculeType = cc ? cc.moleculeType : MoleculeType.unknown + let traceName = '' + if (moleculeType === MoleculeType.protein) { + traceName = 'O' + } else if (moleculeType === MoleculeType.DNA) { + traceName = 'O4\'' + } else if (moleculeType === MoleculeType.RNA) { + traceName = 'C3\'' + } + return traceName +} + +function getDirectionElement2(model: Model, residueModelSegment: Segmentation.Segment<Element>) { + const traceName = getDirectionName2(model, residueModelSegment.index) + + for (let j = residueModelSegment.start, _j = residueModelSegment.end; j < _j; j++) { + if (model.atomicHierarchy.atoms.label_atom_id.value(j) === traceName) return j + } + console.log('direction name element not found', { ...residueModelSegment }) + return residueModelSegment.start +} + /** Iterates over consecutive pairs of residues/coarse elements in polymers */ @@ -268,8 +298,8 @@ export class CoarsePolymerBackboneIterator<T extends number = number> implements /** - * Iterates over individual residues/coarse elements in polymers while providing information - * about the neighbourhood in the underlying model for drawing splines + * Iterates over individual residues/coarse elements in polymers of a unit while + * providing information about the neighbourhood in the underlying model for drawing splines */ export function PolymerTraceIterator(unit: Unit): Iterator<PolymerTraceElement> { switch (unit.kind) { @@ -285,51 +315,63 @@ interface PolymerTraceElement { index: number first: boolean last: boolean - c0: Vec3 - c1: Vec3 - c2: Vec3 - c3: Vec3 - c4: Vec3 + + t0: Vec3 + t1: Vec3 + t2: Vec3 + t3: Vec3 + t4: Vec3 + t5: Vec3 + t6: Vec3 + + d12: Vec3 + d23: Vec3 + d34: Vec3 + d45: Vec3 } -function createPolymerTraceElement (unit: Unit) { +function createPolymerTraceElement (unit: Unit): PolymerTraceElement { return { center: Element.Location(unit), index: 0, first: false, last: false, - c0: Vec3.zero(), - c1: Vec3.zero(), - c2: Vec3.zero(), - c3: Vec3.zero(), - c4: Vec3.zero() + + t0: Vec3.zero(), + t1: Vec3.zero(), + t2: Vec3.zero(), + t3: Vec3.zero(), + t4: Vec3.zero(), + t5: Vec3.zero(), + t6: Vec3.zero(), + + d12: Vec3.zero(), + d23: Vec3.zero(), + d34: Vec3.zero(), + d45: Vec3.zero(), } } const enum AtomicPolymerTraceIteratorState { nextPolymer, nextResidue } -function setSegment (outSegment: Segmentation.Segment<Element>, index: number, segments: Segmentation<Element>, boundingSegment: Segmentation.Segment<Element>): Segmentation.Segment<Element> { - index = Math.min(Math.max(0, index), segments.segments.length - 2) - outSegment.index = index - outSegment.start = segments.segments[index] - outSegment.end = segments.segments[index + 1] +function setSegment (outSegment: Segmentation.Segment<Element>, index: number, segments: Segmentation<Element>, min: number, max: number): Segmentation.Segment<Element> { + // index = Math.min(Math.max(0, index), segments.segments.length - 2) + const _index = Math.min(Math.max(min, index), max) + if (isNaN(_index)) console.log(_index, index, min, max) + outSegment.index = _index + outSegment.start = segments.segments[_index] + outSegment.end = segments.segments[_index + 1] + // console.log(index, {...outSegment}, {...boundingSegment}, segments.segments[boundingSegment.index]) return outSegment } -// const p0 = Vec3.zero() -// const p1 = Vec3.zero() -// const p2 = Vec3.zero() -// const p3 = Vec3.zero() -// const p4 = Vec3.zero() -// const p5 = Vec3.zero() -// const p6 = Vec3.zero() - export class AtomicPolymerTraceIterator<T extends number = number> implements Iterator<PolymerTraceElement> { private value: PolymerTraceElement private polymerIt: SegmentIterator<Element> private residueIt: SegmentIterator<Element> - private polymerSegment: Segmentation.Segment<Element> + private residueSegmentMin: number + private residueSegmentMax: number private state: AtomicPolymerTraceIteratorState = AtomicPolymerTraceIteratorState.nextPolymer private residueSegments: Segmentation<Element> @@ -345,42 +387,62 @@ export class AtomicPolymerTraceIterator<T extends number = number> implements It target[2] = this.unit.model.atomicConformation.z[index] } + updateResidueSegmentRange(polymerSegment: Segmentation.Segment<Element>) { + const { polymerSegments, residueSegments } = this.unit.model.atomicHierarchy + const sMin = polymerSegments.segments[polymerSegment.index] + const sMax = polymerSegments.segments[polymerSegment.index + 1] - 1 + this.residueSegmentMin = residueSegments.segmentMap[sMin] + this.residueSegmentMax = residueSegments.segmentMap[sMax] + } + move() { const { residueIt, polymerIt, value } = this - value.first = false - value.last = false if (this.state === AtomicPolymerTraceIteratorState.nextPolymer) { if (polymerIt.hasNext) { - this.polymerSegment = polymerIt.move(); - residueIt.setSegment(this.polymerSegment); + const polymerSegment = polymerIt.move(); + residueIt.setSegment(polymerSegment); + this.updateResidueSegmentRange(polymerSegment) this.state = AtomicPolymerTraceIteratorState.nextResidue - value.first = true } } if (this.state === AtomicPolymerTraceIteratorState.nextResidue) { + const { tmpSegment, residueSegments, residueSegmentMin, residueSegmentMax } = this const residueSegment = residueIt.move(); + const resSegIdx = residueSegment.index value.index = setTraceElement(value.center, residueSegment) - setSegment(this.tmpSegment, residueSegment.index - 2, this.residueSegments, this.polymerSegment) - this.pos(value.c0, getTraceElement2(this.unit.model, this.tmpSegment)) + setSegment(tmpSegment, resSegIdx - 3, residueSegments, residueSegmentMin, residueSegmentMax) + this.pos(value.t0, getTraceElement2(this.unit.model, tmpSegment)) + + setSegment(tmpSegment, resSegIdx - 2, residueSegments, residueSegmentMin, residueSegmentMax) + this.pos(value.t1, getTraceElement2(this.unit.model, tmpSegment)) + this.pos(value.d12, getDirectionElement2(this.unit.model, tmpSegment)) + + setSegment(tmpSegment, resSegIdx - 1, residueSegments, residueSegmentMin, residueSegmentMax) + this.pos(value.t2, getTraceElement2(this.unit.model, tmpSegment)) + this.pos(value.d23, getDirectionElement2(this.unit.model, tmpSegment)) + + setSegment(tmpSegment, resSegIdx, residueSegments, residueSegmentMin, residueSegmentMax) + this.pos(value.t3, getTraceElement2(this.unit.model, tmpSegment)) + this.pos(value.d34, getDirectionElement2(this.unit.model, tmpSegment)) - setSegment(this.tmpSegment, residueSegment.index - 1, this.residueSegments, this.polymerSegment) - this.pos(value.c1, getTraceElement2(this.unit.model, this.tmpSegment)) + setSegment(tmpSegment, resSegIdx + 1, residueSegments, residueSegmentMin, residueSegmentMax) + this.pos(value.t4, getTraceElement2(this.unit.model, tmpSegment)) + this.pos(value.d45, getDirectionElement2(this.unit.model, tmpSegment)) - setSegment(this.tmpSegment, residueSegment.index, this.residueSegments, this.polymerSegment) - this.pos(value.c2, getTraceElement2(this.unit.model, this.tmpSegment)) + setSegment(tmpSegment, resSegIdx + 2, residueSegments, residueSegmentMin, residueSegmentMax) + this.pos(value.t5, getTraceElement2(this.unit.model, tmpSegment)) - setSegment(this.tmpSegment, residueSegment.index + 1, this.residueSegments, this.polymerSegment) - this.pos(value.c3, getTraceElement2(this.unit.model, this.tmpSegment)) + setSegment(tmpSegment, resSegIdx + 3, residueSegments, residueSegmentMin, residueSegmentMax) + this.pos(value.t6, getTraceElement2(this.unit.model, tmpSegment)) - setSegment(this.tmpSegment, residueSegment.index + 2, this.residueSegments, this.polymerSegment) - this.pos(value.c4, getTraceElement2(this.unit.model, this.tmpSegment)) + value.first = resSegIdx === residueSegmentMin + value.last = resSegIdx === residueSegmentMax if (!residueIt.hasNext) { this.state = AtomicPolymerTraceIteratorState.nextPolymer - value.last = true } } diff --git a/src/mol-geo/shape/mesh-builder.ts b/src/mol-geo/shape/mesh-builder.ts index 6eed0f441cc4772eb606763c1f731e67880c964c..a7f9cf3a2463ed1fec0443d902efdcf7ebd181a0 100644 --- a/src/mol-geo/shape/mesh-builder.ts +++ b/src/mol-geo/shape/mesh-builder.ts @@ -27,6 +27,7 @@ export interface MeshBuilder { addDoubleCylinder(start: Vec3, end: Vec3, lengthScale: number, shift: Vec3, props: CylinderProps): void addFixedCountDashedCylinder(start: Vec3, end: Vec3, lengthScale: number, segmentCount: number, props: CylinderProps): void addIcosahedron(center: Vec3, radius: number, detail: number): void + addTube(controlPoints: Helpers.NumberArray, torsionVectors: Helpers.NumberArray, normalVectors: Helpers.NumberArray, linearSegments: number, radialSegments: number): void setId(id: number): void getMesh(): Mesh } @@ -175,6 +176,84 @@ export namespace MeshBuilder { setIcosahedronMat(tmpIcosahedronMat, center) add(tmpIcosahedronMat, vertices, normals, indices) }, + addTube: (controlPoints: Helpers.NumberArray, torsionVectors: Helpers.NumberArray, normalVectors: Helpers.NumberArray, linearSegments: number, radialSegments: number) => { + console.log(controlPoints, torsionVectors, normalVectors, linearSegments, radialSegments) + + const ico = getIcosahedron({ radius: 0.1, detail: 1 }) + + const radialVector = Vec3.zero() + const normalVector = Vec3.zero() + const tempPos = Vec3.zero() + const a = Vec3.zero() + const b = Vec3.zero() + const u = Vec3.zero() + const v = Vec3.zero() + + const waveFactor = 1 + const width = 0.6 + const height = 0.2 + + const vertexCount = vertices.elementCount + const di = 1 / linearSegments + + for (let i = 0; i <= linearSegments; ++i) { + const i3 = i * 3 + Vec3.fromArray(u, torsionVectors, i3) + Vec3.fromArray(v, normalVectors, i3) + + 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; + + for (let j = 0; j < radialSegments; ++j) { + let t = 2 * Math.PI * j / radialSegments; + + Vec3.copy(a, u) + Vec3.copy(b, v) + Vec3.add( + radialVector, + Vec3.scale(a, a, w * Math.cos(t)), + Vec3.scale(b, b, h * Math.sin(t)) + ) + + Vec3.copy(a, u) + Vec3.copy(b, v) + Vec3.add( + normalVector, + Vec3.scale(a, a, h * Math.cos(t)), + Vec3.scale(b, b, w * Math.sin(t)) + ) + Vec3.normalize(normalVector, normalVector) + + Vec3.fromArray(tempPos, controlPoints, i3) + Vec3.add(tempPos, tempPos, radialVector) + + ChunkedArray.add3(vertices, tempPos[0], tempPos[1], tempPos[2]); + ChunkedArray.add3(normals, normalVector[0], normalVector[1], normalVector[2]); + ChunkedArray.add(ids, currentId); + + // setIcosahedronMat(tmpIcosahedronMat, tempPos) + // add(tmpIcosahedronMat, ico.vertices, ico.normals, ico.indices) + } + } + + for (let i = 0; i < linearSegments; ++i) { + for (let j = 0; j < radialSegments; ++j) { + ChunkedArray.add3( + indices, + (vertexCount + i * radialSegments + (j + 1) % radialSegments), + (vertexCount + (i + 1) * radialSegments + (j + 1) % radialSegments), + (vertexCount + i * radialSegments + j) + ); + ChunkedArray.add3( + indices, + (vertexCount + (i + 1) * radialSegments + (j + 1) % radialSegments), + (vertexCount + (i + 1) * radialSegments + j), + (vertexCount + i * radialSegments + j) + ); + } + } + }, setId: (id: number) => { if (currentId !== id) { currentId = id diff --git a/src/mol-math/linear-algebra/3d/vec3.ts b/src/mol-math/linear-algebra/3d/vec3.ts index 55c138fe3bbad7e1ef13dad567355e3ea01bd8a5..071ce1785a922e282f2aecb4d205872f4590ff08 100644 --- a/src/mol-math/linear-algebra/3d/vec3.ts +++ b/src/mol-math/linear-algebra/3d/vec3.ts @@ -380,6 +380,13 @@ namespace Vec3 { return v[0] === 0 && v[1] === 0 && v[2] === 0 } + export function projectPointOnVector(out: Vec3, point: Vec3, vector: Vec3, origin: Vec3) { + // point.sub(origin).projectOnVector(vector).add(origin) + Vec3.sub(out, Vec3.copy(out, point), origin) + const scalar = Vec3.dot(vector, out) / Vec3.squaredMagnitude(vector); + return Vec3.add(out, Vec3.scale(out, Vec3.copy(out, vector), scalar), origin); + } + export function toString(a: Vec3) { return `[${a[0]} ${a[1]} ${a[2]}]`; } diff --git a/src/mol-view/stage.ts b/src/mol-view/stage.ts index 34c85ffca360ea256642a3d7cf13d14fdbb4122c..a7bdc552848e1883f007f4b967d424c6f22907c5 100644 --- a/src/mol-view/stage.ts +++ b/src/mol-view/stage.ts @@ -73,14 +73,14 @@ export class Stage { // this.loadPdbid('1jj2') // this.loadPdbid('4umt') // ligand has bond with order 3 - // this.loadPdbid('1crn') // small + this.loadPdbid('1crn') // small // this.loadPdbid('1hrv') // viral assembly // this.loadPdbid('1rb8') // virus // this.loadPdbid('1blu') // metal coordination // this.loadPdbid('3pqr') // inter unit bonds // this.loadPdbid('4v5a') // ribosome // this.loadPdbid('3j3q') // ... - this.loadPdbid('3sn6') // discontinuous chains + // this.loadPdbid('3sn6') // discontinuous chains // this.loadMmcifUrl(`../../examples/1cbs_full.bcif`) // this.loadMmcifUrl(`../../../test/pdb-dev/PDBDEV_00000001.cif`) // ok @@ -103,7 +103,7 @@ export class Stage { const modelEntity = await MmcifUrlToModel.apply(this.ctx, urlEntity) const structureEntity = await ModelToStructure.apply(this.ctx, modelEntity) - // StructureToBallAndStick.apply(this.ctx, structureEntity, { ...ballAndStickProps, visible: true }) + StructureToBallAndStick.apply(this.ctx, structureEntity, { ...ballAndStickProps, visible: false }) StructureToSpacefill.apply(this.ctx, structureEntity, { ...spacefillProps, visible: false }) StructureToDistanceRestraint.apply(this.ctx, structureEntity, { ...distanceRestraintProps, visible: false }) // StructureToBackbone.apply(this.ctx, structureEntity, { ...backboneProps, visible: true }) @@ -111,13 +111,14 @@ export class Stage { this.globalContext.components.sequenceView.setState({ structure: structureEntity.value }); - const structureEntity2 = await ModelToStructure.apply(this.ctx, modelEntity) - const q1 = Q.generators.atoms({ - residueTest: l => SP.residue.label_seq_id(l) > 30 - }); - structureEntity2.value = Selection.unionStructure(await Query(q1)(structureEntity2.value).run()); - StructureToBackbone.apply(this.ctx, structureEntity2, { ...backboneProps, visible: true }) - StructureToCartoon.apply(this.ctx, structureEntity2, { ...cartoonProps, visible: true }) + // const structureEntity2 = await ModelToStructure.apply(this.ctx, modelEntity) + // const q1 = Q.generators.atoms({ + // residueTest: l => SP.residue.label_seq_id(l) < 10 + // }); + // structureEntity2.value = Selection.unionStructure(await Query(q1)(structureEntity2.value).run()); + // StructureToBackbone.apply(this.ctx, structureEntity2, { ...backboneProps, visible: true }) + // StructureToCartoon.apply(this.ctx, structureEntity2, { ...cartoonProps, visible: true }) + // StructureToBallAndStick.apply(this.ctx, structureEntity2, { ...ballAndStickProps, visible: true }) } loadPdbid (pdbid: string) {