Skip to content
Snippets Groups Projects
Select Git revision
  • 66b9f6104c1104255a527f6af92e8c80b319f1ac
  • master default protected
  • rednatco-v2
  • base-pairs-ladder
  • rednatco
  • test
  • ntc-tube-uniform-color
  • ntc-tube-missing-atoms
  • restore-vertex-array-per-program
  • watlas2
  • dnatco_new
  • cleanup-old-nodejs
  • webmmb
  • fix_auth_seq_id
  • update_deps
  • ext_dev
  • ntc_balls
  • nci-2
  • plugin
  • bugfix-0.4.5
  • nci
  • v0.5.0-dev.1
  • v0.4.5
  • v0.4.4
  • v0.4.3
  • v0.4.2
  • v0.4.1
  • v0.4.0
  • v0.3.12
  • v0.3.11
  • v0.3.10
  • v0.3.9
  • v0.3.8
  • v0.3.7
  • v0.3.6
  • v0.3.5
  • v0.3.4
  • v0.3.3
  • v0.3.2
  • v0.3.1
  • v0.3.0
41 results

carbohydrate-terminal-link-cylinder.ts

Blame
  • carbohydrate-terminal-link-cylinder.ts 7.32 KiB
    /**
     * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
     *
     * @author Alexander Rose <alexander.rose@weirdbyte.de>
     */
    
    import { ParamDefinition as PD } from '../../../mol-util/param-definition';
    import { VisualContext } from '../../visual';
    import { Structure, StructureElement, Link } from '../../../mol-model/structure';
    import { Theme } from '../../../mol-theme/theme';
    import { Mesh } from '../../../mol-geo/geometry/mesh/mesh';
    import { Vec3 } from '../../../mol-math/linear-algebra';
    import { BitFlags } from '../../../mol-util';
    import { LinkType } from '../../../mol-model/structure/model/types';
    import { createLinkCylinderMesh, LinkCylinderParams } from './util/link';
    import { UnitsMeshParams } from '../units-visual';
    import { ComplexVisual, ComplexMeshVisual } from '../complex-visual';
    import { VisualUpdateState } from '../../util';
    import { LocationIterator } from '../../../mol-geo/util/location-iterator';
    import { OrderedSet, Interval } from '../../../mol-data/int';
    import { PickingId } from '../../../mol-geo/geometry/picking';
    import { EmptyLoci, Loci } from '../../../mol-model/loci';
    
    function createCarbohydrateTerminalLinkCylinderMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: PD.Values<CarbohydrateTerminalLinkParams>, mesh?: Mesh) {
        const { terminalLinks, elements } = structure.carbohydrates
        const { linkSizeFactor } = props
    
        const location = StructureElement.create()
    
        const builderProps = {
            linkCount: terminalLinks.length,
            referencePosition: (edgeIndex: number) => null,
            position: (posA: Vec3, posB: Vec3, edgeIndex: number) => {
                const l = terminalLinks[edgeIndex]
                if (l.fromCarbohydrate) {
                    Vec3.copy(posA, elements[l.carbohydrateIndex].geometry.center)
                    l.elementUnit.conformation.position(l.elementUnit.elements[l.elementIndex], posB)
                } else {
                    l.elementUnit.conformation.position(l.elementUnit.elements[l.elementIndex], posA)
                    Vec3.copy(posB, elements[l.carbohydrateIndex].geometry.center)
                }
            },
            order: (edgeIndex: number) => 1,
            flags: (edgeIndex: number) => BitFlags.create(LinkType.Flag.None),
            radius: (edgeIndex: number) => {
                const l = terminalLinks[edgeIndex]
                if (l.fromCarbohydrate) {
                    location.unit = elements[l.carbohydrateIndex].unit
                    location.element = elements[l.carbohydrateIndex].anomericCarbon
                } else {
                    location.unit = l.elementUnit
                    location.element = l.elementUnit.elements[l.elementIndex]
                }
                return theme.size.size(location) * linkSizeFactor
            },
            ignore: (edgeIndex: number) => false
        }
    
        return createLinkCylinderMesh(ctx, builderProps, props, mesh)
    }
    
    export const CarbohydrateTerminalLinkParams = {
        ...UnitsMeshParams,
        ...LinkCylinderParams,
        linkSizeFactor: PD.Numeric(0.3, { min: 0, max: 3, step: 0.01 }),
    }
    export type CarbohydrateTerminalLinkParams = typeof CarbohydrateTerminalLinkParams
    
    export function CarbohydrateTerminalLinkVisual(materialId: number): ComplexVisual<CarbohydrateTerminalLinkParams> {
        return ComplexMeshVisual<CarbohydrateTerminalLinkParams>({
            defaultProps: PD.getDefaultValues(CarbohydrateTerminalLinkParams),
            createGeometry: createCarbohydrateTerminalLinkCylinderMesh,
            createLocationIterator: CarbohydrateTerminalLinkIterator,
            getLoci: getTerminalLinkLoci,
            eachLocation: eachTerminalLink,
            setUpdateState: (state: VisualUpdateState, newProps: PD.Values<CarbohydrateTerminalLinkParams>, currentProps: PD.Values<CarbohydrateTerminalLinkParams>) => {
                state.createGeometry = (
                    newProps.linkSizeFactor !== currentProps.linkSizeFactor ||
                    newProps.radialSegments !== currentProps.radialSegments
                )
            }
        }, materialId)
    }
    
    function CarbohydrateTerminalLinkIterator(structure: Structure): LocationIterator {
        const { elements, terminalLinks } = structure.carbohydrates
        const groupCount = terminalLinks.length
        const instanceCount = 1
        const location = Link.Location()
        const getLocation = (groupIndex: number) => {
            const terminalLink = terminalLinks[groupIndex]
            const carb = elements[terminalLink.carbohydrateIndex]
            const indexCarb = OrderedSet.indexOf(carb.unit.elements, carb.anomericCarbon)
            if (terminalLink.fromCarbohydrate) {
                location.aUnit = carb.unit
                location.aIndex = indexCarb as StructureElement.UnitIndex
                location.bUnit = terminalLink.elementUnit
                location.bIndex = terminalLink.elementIndex
            } else {
                location.aUnit = terminalLink.elementUnit
                location.aIndex = terminalLink.elementIndex
                location.bUnit = carb.unit
                location.bIndex = indexCarb as StructureElement.UnitIndex
            }
            return location
        }
        return LocationIterator(groupCount, instanceCount, getLocation, true)
    }
    
    function getTerminalLinkLoci(pickingId: PickingId, structure: Structure, id: number) {
        const { objectId, groupId } = pickingId
        if (id === objectId) {
            const { terminalLinks, elements } = structure.carbohydrates
            const l = terminalLinks[groupId]
            const carb = elements[l.carbohydrateIndex]
            const carbIndex = OrderedSet.indexOf(carb.unit.elements, carb.anomericCarbon)
    
            return Link.Loci(structure, [
                Link.Location(
                    carb.unit, carbIndex as StructureElement.UnitIndex,
                    l.elementUnit, l.elementIndex
                ),
                Link.Location(
                    l.elementUnit, l.elementIndex,
                    carb.unit, carbIndex as StructureElement.UnitIndex
                )
            ])
        }
        return EmptyLoci
    }
    
    // TODO for each link when both of the link elements are in a StructureElement.Loci
    function eachTerminalLink(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean) {
        const { getTerminalLinkIndex } = structure.carbohydrates
        let changed = false
        if (Link.isLoci(loci)) {
            if (!Structure.areEquivalent(loci.structure, structure)) return false
            for (const l of loci.links) {
                const idx = getTerminalLinkIndex(l.aUnit, l.aUnit.elements[l.aIndex], l.bUnit, l.bUnit.elements[l.bIndex])
                if (idx !== undefined) {
                    if (apply(Interval.ofSingleton(idx))) changed = true
                }
            }
        } else if (StructureElement.isLoci(loci)) {
            if (!Structure.areEquivalent(loci.structure, structure)) return false
            // TODO mark link only when both of the link elements are in a StructureElement.Loci
            const { getElementIndex, getTerminalLinkIndices, elements } = structure.carbohydrates
            for (const e of loci.elements) {
                OrderedSet.forEach(e.indices, v => {
                    const carbI = getElementIndex(e.unit, e.unit.elements[v])
                    if (carbI !== undefined) {
                        const carb = elements[carbI]
                        const indices = getTerminalLinkIndices(carb.unit, carb.anomericCarbon)
                        for (let i = 0, il = indices.length; i < il; ++i) {
                            if (apply(Interval.ofSingleton(indices[i]))) changed = true
                        }
                    }
                })
            }
        }
        return changed
    }