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

wip, carbohydrate visual refactoring

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