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

wip, carbohydrate visual refactoring

parent 9208dbd6
Branches
Tags
No related merge requests found
...@@ -15,14 +15,13 @@ import { MeshValues } from 'mol-gl/renderable'; ...@@ -15,14 +15,13 @@ import { MeshValues } from 'mol-gl/renderable';
import { getMeshData } from '../../../util/mesh-data'; import { getMeshData } from '../../../util/mesh-data';
import { Mesh } from '../../../shape/mesh'; import { Mesh } from '../../../shape/mesh';
import { PickingId } from '../../../util/picking'; import { PickingId } from '../../../util/picking';
import { createMarkers, MarkerAction, MarkerData } from '../../../util/marker-data'; import { createMarkers, MarkerAction, MarkerData, applyMarkerAction } from '../../../util/marker-data';
import { Loci, EmptyLoci } from 'mol-model/loci'; import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci';
import { SizeTheme } from '../../../theme'; import { SizeTheme } from '../../../theme';
import { createMeshValues, updateMeshValues, updateRenderableState, createRenderableState, DefaultMeshProps } from '../../util'; import { createMeshValues, updateMeshValues, updateRenderableState, createRenderableState, DefaultMeshProps } from '../../util';
import { Vec3 } from 'mol-math/linear-algebra'; import { Vec3 } from 'mol-math/linear-algebra';
import { deepEqual } from 'mol-util'; import { deepEqual } from 'mol-util';
import { LocationIterator } from './util/location-iterator'; import { LocationIterator } from './util/location-iterator';
import { createValueColor } from '../../../util/color-data';
import { createLinkCylinderMesh, DefaultLinkCylinderProps, LinkCylinderProps } from './util/link'; import { createLinkCylinderMesh, DefaultLinkCylinderProps, LinkCylinderProps } from './util/link';
import { OrderedSet } from 'mol-data/int'; import { OrderedSet } from 'mol-data/int';
...@@ -86,7 +85,7 @@ export function CarbohydrateLinkVisual(): StructureVisual<CarbohydrateLinkProps> ...@@ -86,7 +85,7 @@ export function CarbohydrateLinkVisual(): StructureVisual<CarbohydrateLinkProps>
// console.log(mesh) // console.log(mesh)
const transforms = createIdentityTransform() const transforms = createIdentityTransform()
const color = createValueColor(0x119911)//createColors(colorTheme) const color = createColors(createCarbohydrateLinkIterator(structure), colorTheme)
const marker = createMarkers(instanceCount * elementCount) const marker = createMarkers(instanceCount * elementCount)
const counts = { drawCount: mesh.triangleCount * 3, elementCount, instanceCount } const counts = { drawCount: mesh.triangleCount * 3, elementCount, instanceCount }
...@@ -97,8 +96,7 @@ export function CarbohydrateLinkVisual(): StructureVisual<CarbohydrateLinkProps> ...@@ -97,8 +96,7 @@ export function CarbohydrateLinkVisual(): StructureVisual<CarbohydrateLinkProps>
...marker, ...marker,
aTransform: transforms, aTransform: transforms,
elements: mesh.indexBuffer, elements: mesh.indexBuffer,
...createMeshValues(currentProps, counts), ...createMeshValues(currentProps, counts)
aColor: ValueCell.create(new Float32Array(mesh.vertexCount * 3))
} }
const state = createRenderableState(currentProps) const state = createRenderableState(currentProps)
...@@ -111,13 +109,13 @@ export function CarbohydrateLinkVisual(): StructureVisual<CarbohydrateLinkProps> ...@@ -111,13 +109,13 @@ export function CarbohydrateLinkVisual(): StructureVisual<CarbohydrateLinkProps>
let updateColor = false let updateColor = false
// if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) { if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) {
// updateColor = true updateColor = true
// } }
// if (updateColor) { if (updateColor) {
// createColors(LinkIterator.fromGroup(currentGroup), newProps.colorTheme, renderObject.values) createColors(createCarbohydrateLinkIterator(currentStructure), newProps.colorTheme, renderObject.values)
// } }
updateMeshValues(renderObject.values, newProps) updateMeshValues(renderObject.values, newProps)
updateRenderableState(renderObject.state, newProps) updateRenderableState(renderObject.state, newProps)
...@@ -129,8 +127,7 @@ export function CarbohydrateLinkVisual(): StructureVisual<CarbohydrateLinkProps> ...@@ -129,8 +127,7 @@ export function CarbohydrateLinkVisual(): StructureVisual<CarbohydrateLinkProps>
return getLinkLoci(pickingId, currentStructure, renderObject.id) return getLinkLoci(pickingId, currentStructure, renderObject.id)
}, },
mark(loci: Loci, action: MarkerAction) { mark(loci: Loci, action: MarkerAction) {
// TODO markLink(loci, action, currentStructure, renderObject.values)
// markLink(loci, action, currentStructure, renderObject.values)
}, },
destroy() { destroy() {
// TODO // TODO
...@@ -138,6 +135,26 @@ export function CarbohydrateLinkVisual(): StructureVisual<CarbohydrateLinkProps> ...@@ -138,6 +135,26 @@ export function CarbohydrateLinkVisual(): StructureVisual<CarbohydrateLinkProps>
} }
} }
function createCarbohydrateLinkIterator(structure: Structure): LocationIterator {
const { elements, links } = structure.carbohydrates
const elementCount = links.length
const instanceCount = 1
const location = Link.Location()
const getLocation = (elementIndex: number, instanceIndex: number) => {
const link = links[elementIndex]
const carbA = elements[link.carbohydrateIndexA]
const carbB = elements[link.carbohydrateIndexB]
const indexA = OrderedSet.findPredecessorIndex(carbA.unit.elements, carbA.anomericCarbon)
const indexB = OrderedSet.findPredecessorIndex(carbB.unit.elements, carbB.anomericCarbon)
location.aUnit = carbA.unit
location.aIndex = indexA as StructureElement.UnitIndex
location.bUnit = carbB.unit
location.bIndex = indexB as StructureElement.UnitIndex
return location
}
return LocationIterator(elementCount, instanceCount, getLocation)
}
function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) { function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) {
const { objectId, elementId } = pickingId const { objectId, elementId } = pickingId
if (id === objectId) { if (id === objectId) {
...@@ -157,33 +174,31 @@ function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) { ...@@ -157,33 +174,31 @@ function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) {
return EmptyLoci return EmptyLoci
} }
// TODO function markLink(loci: Loci, action: MarkerAction, structure: Structure, values: MarkerData) {
// function markLink(loci: Loci, action: MarkerAction, structure: Structure, values: MarkerData) { const tMarker = values.tMarker
// const tMarker = values.tMarker
const { getLinkIndex } = structure.carbohydrates
// const links = structure.links const elementCount = structure.carbohydrates.elements.length
// const elementCount = links.bondCount
// const instanceCount = 1 let changed = false
const array = tMarker.ref.value.array
// let changed = false if (isEveryLoci(loci)) {
// const array = tMarker.ref.value.array if (applyMarkerAction(array, 0, elementCount, action)) {
// if (isEveryLoci(loci)) { changed = true
// applyMarkerAction(array, 0, elementCount * instanceCount, action) }
// changed = true } else if (Link.isLoci(loci)) {
// } else if (Link.isLoci(loci)) { for (const l of loci.links) {
// for (const b of loci.links) { const idx = getLinkIndex(l.aUnit, l.aUnit.elements[l.aIndex], l.bUnit, l.bUnit.elements[l.bIndex])
// const _idx = structure.links.getBondIndex(b.aIndex, b.aUnit, b.bIndex, b.bUnit) if (idx !== undefined) {
// if (_idx !== -1) { if (applyMarkerAction(array, idx, idx + 1, action) && !changed) {
// const idx = _idx changed = true
// if (applyMarkerAction(array, idx, idx + 1, action) && !changed) { }
// changed = true }
// } }
// } } else {
// } return
// } else { }
// return if (changed) {
// } ValueCell.update(tMarker, tMarker.ref.value)
// if (changed) { }
// ValueCell.update(tMarker, tMarker.ref.value) }
// } \ No newline at end of file
// }
\ No newline at end of file
...@@ -141,7 +141,7 @@ export function CarbohydrateSymbolVisual(): StructureVisual<CarbohydrateSymbolPr ...@@ -141,7 +141,7 @@ export function CarbohydrateSymbolVisual(): StructureVisual<CarbohydrateSymbolPr
mesh = await createCarbohydrateSymbolMesh(ctx, currentStructure, mesh) mesh = await createCarbohydrateSymbolMesh(ctx, currentStructure, mesh)
const transforms = createIdentityTransform() const transforms = createIdentityTransform()
const color = createColors(createCarbohydrateIterator(structure), colorTheme) const color = createColors(createCarbohydrateElementIterator(structure), colorTheme)
const marker = createMarkers(instanceCount * elementCount) const marker = createMarkers(instanceCount * elementCount)
const counts = { drawCount: mesh.triangleCount * 3, elementCount, instanceCount } const counts = { drawCount: mesh.triangleCount * 3, elementCount, instanceCount }
...@@ -152,8 +152,7 @@ export function CarbohydrateSymbolVisual(): StructureVisual<CarbohydrateSymbolPr ...@@ -152,8 +152,7 @@ export function CarbohydrateSymbolVisual(): StructureVisual<CarbohydrateSymbolPr
...marker, ...marker,
aTransform: transforms, aTransform: transforms,
elements: mesh.indexBuffer, elements: mesh.indexBuffer,
...createMeshValues(currentProps, counts), ...createMeshValues(currentProps, counts)
aColor: ValueCell.create(new Float32Array(mesh.vertexCount * 3))
} }
const state = createRenderableState(currentProps) const state = createRenderableState(currentProps)
...@@ -171,7 +170,7 @@ export function CarbohydrateSymbolVisual(): StructureVisual<CarbohydrateSymbolPr ...@@ -171,7 +170,7 @@ export function CarbohydrateSymbolVisual(): StructureVisual<CarbohydrateSymbolPr
} }
if (updateColor) { if (updateColor) {
createColors(createCarbohydrateIterator(currentStructure), newProps.colorTheme, renderObject.values) createColors(createCarbohydrateElementIterator(currentStructure), newProps.colorTheme, renderObject.values)
} }
updateMeshValues(renderObject.values, newProps) updateMeshValues(renderObject.values, newProps)
...@@ -192,13 +191,13 @@ export function CarbohydrateSymbolVisual(): StructureVisual<CarbohydrateSymbolPr ...@@ -192,13 +191,13 @@ export function CarbohydrateSymbolVisual(): StructureVisual<CarbohydrateSymbolPr
} }
} }
function createCarbohydrateIterator(structure: Structure): LocationIterator { function createCarbohydrateElementIterator(structure: Structure): LocationIterator {
const carbs = structure.carbohydrates.elements const carbElements = structure.carbohydrates.elements
const elementCount = carbs.length const elementCount = carbElements.length
const instanceCount = 1 const instanceCount = 1
const location = StructureElement.create() const location = StructureElement.create()
const getLocation = (elementIndex: number, instanceIndex: number) => { const getLocation = (elementIndex: number, instanceIndex: number) => {
const carb = carbs[elementIndex] const carb = carbElements[elementIndex]
location.unit = carb.unit location.unit = carb.unit
location.element = carb.anomericCarbon location.element = carb.anomericCarbon
return location return location
...@@ -221,7 +220,7 @@ function getCarbohydrateLoci(pickingId: PickingId, structure: Structure, id: num ...@@ -221,7 +220,7 @@ function getCarbohydrateLoci(pickingId: PickingId, structure: Structure, id: num
function markCarbohydrate(loci: Loci, action: MarkerAction, structure: Structure, values: MarkerData) { function markCarbohydrate(loci: Loci, action: MarkerAction, structure: Structure, values: MarkerData) {
const tMarker = values.tMarker const tMarker = values.tMarker
const { byUnitAndElement } = structure.carbohydrates const { getElementIndex } = structure.carbohydrates
const elementCount = structure.carbohydrates.elements.length const elementCount = structure.carbohydrates.elements.length
let changed = false let changed = false
...@@ -233,7 +232,7 @@ function markCarbohydrate(loci: Loci, action: MarkerAction, structure: Structure ...@@ -233,7 +232,7 @@ function markCarbohydrate(loci: Loci, action: MarkerAction, structure: Structure
} else if (StructureElement.isLoci(loci)) { } else if (StructureElement.isLoci(loci)) {
for (const e of loci.elements) { for (const e of loci.elements) {
OrderedSet.forEach(e.indices, index => { OrderedSet.forEach(e.indices, index => {
const idx = byUnitAndElement(e.unit, e.unit.elements[index]) const idx = getElementIndex(e.unit, e.unit.elements[index])
if (idx !== undefined) { if (idx !== undefined) {
if (applyMarkerAction(array, idx, idx + 1, action) && !changed) { if (applyMarkerAction(array, idx, idx + 1, action) && !changed) {
changed = true changed = true
......
...@@ -144,13 +144,13 @@ function markLink(loci: Loci, action: MarkerAction, structure: Structure, values ...@@ -144,13 +144,13 @@ function markLink(loci: Loci, action: MarkerAction, structure: Structure, values
const links = structure.links const links = structure.links
const elementCount = links.bondCount const elementCount = links.bondCount
const instanceCount = 1
let changed = false let changed = false
const array = tMarker.ref.value.array const array = tMarker.ref.value.array
if (isEveryLoci(loci)) { if (isEveryLoci(loci)) {
applyMarkerAction(array, 0, elementCount * instanceCount, action) if (applyMarkerAction(array, 0, elementCount, action)) {
changed = true changed = true
}
} else if (Link.isLoci(loci)) { } else if (Link.isLoci(loci)) {
for (const b of loci.links) { for (const b of loci.links) {
const _idx = structure.links.getBondIndex(b.aIndex, b.aUnit, b.bIndex, b.bUnit) const _idx = structure.links.getBondIndex(b.aIndex, b.aUnit, b.bIndex, b.bUnit)
......
...@@ -126,7 +126,7 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates { ...@@ -126,7 +126,7 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates {
const elementsWithRingMap = new Map<string, number>() const elementsWithRingMap = new Map<string, number>()
function elementKey(residueIndex: number, unitId: number, altId: string) { function ringElementKey(residueIndex: number, unitId: number, altId: string) {
return `${residueIndex}|${unitId}|${altId}` return `${residueIndex}|${unitId}|${altId}`
} }
...@@ -194,7 +194,7 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates { ...@@ -194,7 +194,7 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates {
const altId = getRingAltId(unit, ringAtoms) const altId = getRingAltId(unit, ringAtoms)
const elementIndex = elements.length const elementIndex = elements.length
ringElements.push(elementIndex) ringElements.push(elementIndex)
elementsWithRingMap.set(elementKey(residueIndex, unit.id, altId), elementIndex) elementsWithRingMap.set(ringElementKey(residueIndex, unit.id, altId), elementIndex)
elements.push({ elements.push({
geometry: { center, normal, direction }, geometry: { center, normal, direction },
component: saccharideComp, component: saccharideComp,
...@@ -227,8 +227,8 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates { ...@@ -227,8 +227,8 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates {
} }
} }
function getElementIndex(unit: Unit.Atomic, index: StructureElement.UnitIndex) { function getRingElementIndex(unit: Unit.Atomic, index: StructureElement.UnitIndex) {
return elementsWithRingMap.get(elementKey(unit.getResidueIndex(index), unit.id, getAltId(unit, index))) return elementsWithRingMap.get(ringElementKey(unit.getResidueIndex(index), unit.id, getAltId(unit, index)))
} }
// get carbohydrate links induced by inter-unit bonds // get carbohydrate links induced by inter-unit bonds
...@@ -241,32 +241,32 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates { ...@@ -241,32 +241,32 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates {
pairBonds.getBonds(indexA).forEach(bondInfo => { pairBonds.getBonds(indexA).forEach(bondInfo => {
const { unitA, unitB } = pairBonds const { unitA, unitB } = pairBonds
const indexB = bondInfo.indexB const indexB = bondInfo.indexB
const elementIndexA = getElementIndex(unitA, indexA) const ringElementIndexA = getRingElementIndex(unitA, indexA)
const elementIndexB = getElementIndex(unitB, indexB) const ringElementIndexB = getRingElementIndex(unitB, indexB)
if (elementIndexA !== undefined && elementIndexB !== undefined) { if (ringElementIndexA !== undefined && ringElementIndexB !== undefined) {
const atomIdA = getAtomId(unitA, indexA) const atomIdA = getAtomId(unitA, indexA)
if (atomIdA.startsWith('O1') || atomIdA.startsWith('C1')) { if (atomIdA.startsWith('O1') || atomIdA.startsWith('C1')) {
fixLinkDirection(elementIndexA, elementIndexB) fixLinkDirection(ringElementIndexA, ringElementIndexB)
} }
links.push({ links.push({
carbohydrateIndexA: elementIndexA, carbohydrateIndexA: ringElementIndexA,
carbohydrateIndexB: elementIndexB carbohydrateIndexB: ringElementIndexB
}) })
} else if (elementIndexA !== undefined) { } else if (ringElementIndexA !== undefined) {
const atomIdA = getAtomId(unitA, indexA) const atomIdA = getAtomId(unitA, indexA)
if (atomIdA.startsWith('O1') || atomIdA.startsWith('C1')) { if (atomIdA.startsWith('O1') || atomIdA.startsWith('C1')) {
fixTerminalLinkDirection(elementIndexA, indexB, unitB) fixTerminalLinkDirection(ringElementIndexA, indexB, unitB)
} }
terminalLinks.push({ terminalLinks.push({
carbohydrateIndex: elementIndexA, carbohydrateIndex: ringElementIndexA,
elementIndex: indexB, elementIndex: indexB,
elementUnit: unitB, elementUnit: unitB,
fromCarbohydrate: true fromCarbohydrate: true
}) })
} else if (elementIndexB !== undefined) { } else if (ringElementIndexB !== undefined) {
terminalLinks.push({ terminalLinks.push({
carbohydrateIndex: elementIndexB, carbohydrateIndex: ringElementIndexB,
elementIndex: indexA, elementIndex: indexA,
elementUnit: unitA, elementUnit: unitA,
fromCarbohydrate: false fromCarbohydrate: false
...@@ -277,20 +277,43 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates { ...@@ -277,20 +277,43 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates {
}) })
} }
// build lookup map return { links, terminalLinks, elements, partialElements, ...buildLookups(elements, links) }
const map = new Map<string, number>() }
function buildLookups (elements: CarbohydrateElement[], links: CarbohydrateLink[]) {
// element lookup
function elementKey(unit: Unit, anomericCarbon: ElementIndex) {
return `${unit.id}|${anomericCarbon}`
}
const elementMap = new Map<string, number>()
for (let i = 0, il = elements.length; i < il; ++i) { for (let i = 0, il = elements.length; i < il; ++i) {
const { unit, anomericCarbon } = elements[i] const { unit, anomericCarbon } = elements[i]
map.set(key(unit, anomericCarbon), i) elementMap.set(elementKey(unit, anomericCarbon), i)
} }
function key(unit: Unit, anomericCarbon: ElementIndex) { function getElementIndex(unit: Unit, anomericCarbon: ElementIndex) {
return `${unit.id}|${anomericCarbon}` return elementMap.get(elementKey(unit, anomericCarbon))
}
// link lookup
function linkKey(unitA: Unit, anomericCarbonA: ElementIndex, unitB: Unit, anomericCarbonB: ElementIndex) {
return `${unitA.id}|${anomericCarbonA}|${unitB.id}|${anomericCarbonB}`
}
const linkMap = new Map<string, number>()
for (let i = 0, il = links.length; i < il; ++i) {
const l = links[i]
const { unit: unitA, anomericCarbon: anomericCarbonA } = elements[l.carbohydrateIndexA]
const { unit: unitB, anomericCarbon: anomericCarbonB } = elements[l.carbohydrateIndexB]
linkMap.set(linkKey(unitA, anomericCarbonA, unitB, anomericCarbonB), i)
} }
function byUnitAndElement(unit: Unit, anomericCarbon: ElementIndex) { function getLinkIndex(unitA: Unit, anomericCarbonA: ElementIndex, unitB: Unit, anomericCarbonB: ElementIndex) {
return map.get(key(unit, anomericCarbon)) return linkMap.get(linkKey(unitA, anomericCarbonA, unitB, anomericCarbonB))
} }
return { links, terminalLinks, elements, partialElements, byUnitAndElement } return { getElementIndex, getLinkIndex }
} }
\ No newline at end of file
...@@ -42,5 +42,6 @@ export interface Carbohydrates { ...@@ -42,5 +42,6 @@ export interface Carbohydrates {
terminalLinks: ReadonlyArray<CarbohydrateTerminalLink> terminalLinks: ReadonlyArray<CarbohydrateTerminalLink>
elements: ReadonlyArray<CarbohydrateElement> elements: ReadonlyArray<CarbohydrateElement>
partialElements: ReadonlyArray<PartialCarbohydrateElement> partialElements: ReadonlyArray<PartialCarbohydrateElement>
byUnitAndElement: (unit: Unit, element: ElementIndex) => number | undefined getElementIndex: (unit: Unit, anomericCarbon: ElementIndex) => number | undefined
getLinkIndex: (unitA: Unit, anomericCarbonA: ElementIndex, unitB: Unit, anomericCarbonB: ElementIndex) => number | undefined
} }
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment