NGL@1.0.0-beta.7 Home Manual Reference Source Gallery

src/geometry/contact-utils.js

/**
 * @file Contact Utils
 * @author Alexander Rose <alexander.rose@weirdbyte.de>
 * @private
 */

import { Vector3 } from '../../lib/three.es6.js'

import { radToDeg } from '../math/math-utils.js'
import Contact from './contact.js'
import Selection from '../selection/selection.js'

function polarContacts (structure, maxDistance, maxAngle) {
  maxDistance = maxDistance || 3.5
  maxAngle = maxAngle || 40

  var donorSelection = new Selection(
    '( ARG and ( .NE or .NH1 or .NH2 ) ) or ' +
    '( ASP and .ND2 ) or ' +
    '( GLN and .NE2 ) or ' +
    '( HIS and ( .ND1 or .NE2 ) ) or ' +
    '( LYS and .NZ ) or ' +
    '( SER and .OG ) or ' +
    '( THR and .OG1 ) or ' +
    '( TRP and .NE1 ) or ' +
    '( TYR and .OH ) or ' +
    '( PROTEIN and .N )'
  )

  var acceptorSelection = new Selection(
    '( ASN and .OD1 ) or ' +
    '( ASP and ( OD1 or .OD2 ) ) or ' +
    '( GLN and .OE1 ) or ' +
    '( GLU and ( .OE1 or .OE2 ) ) or ' +
    '( HIS and ( .ND1 or .NE2 ) ) or ' +
    '( SER and .OG ) or ' +
    '( THR and .OG1 ) or ' +
    '( TYR and .OH ) or ' +
    '( PROTEIN and .O )'
  )

  var donorView = structure.getView(donorSelection)
  var acceptorView = structure.getView(acceptorSelection)

  var contact = new Contact(donorView, acceptorView)
  var data = contact.within(maxDistance)
  var bondStore = data.bondStore

  var ap1 = structure.getAtomProxy()
  var ap2 = structure.getAtomProxy()
  var atomCA = structure.getAtomProxy()
  var atomC = structure.getAtomProxy()
  var rp = structure.getResidueProxy()
  var rpPrev = structure.getResidueProxy()
  var v1 = new Vector3()
  var v2 = new Vector3()

  var checkAngle = function (atom1, atom2, oName, cName) {
    var atomO, atomN

    if (atom1.atomname === oName) {
      atomO = atom1
      atomN = atom2
    } else {
      atomO = atom2
      atomN = atom1
    }

    rp.index = atomO.residueIndex
    var atomC = rp.getAtomIndexByName(cName)

    v1.subVectors(atomC, atomO)
    v2.subVectors(atomC, atomN)

    return radToDeg(v1.angleTo(v2)) < maxAngle
  }

  for (var i = 0, il = bondStore.count; i < il; ++i) {
    ap1.index = bondStore.atomIndex1[ i ]
    ap2.index = bondStore.atomIndex2[ i ]

    if ((ap1.atomname === 'O' && ap2.atomname === 'N') ||
        (ap1.atomname === 'N' && ap2.atomname === 'O')
    ) {
      // ignore backbone to backbone contacts
      data.bondSet.clear(i)
      continue
    } else if (ap1.atomname === 'N' || ap2.atomname === 'N') {
      var atomN, atomX

      if (ap1.atomname === 'N') {
        atomN = ap1
        atomX = ap2
      } else {
        atomN = ap2
        atomX = ap1
      }

      rp.index = atomN.residueIndex
      atomCA.index = rp.getAtomIndexByName('CA')
      if (atomCA.index === undefined) continue

      var prevRes = rp.getPreviousConnectedResidue(rpPrev)
      if (prevRes === undefined) continue

      atomC.index = prevRes.getAtomIndexByName('C')
      if (atomC.index === undefined) continue

      v1.subVectors(atomN, atomC)
      v2.subVectors(atomN, atomCA)
      v1.add(v2).multiplyScalar(0.5)
      v2.subVectors(atomX, atomN)

      if (radToDeg(v1.angleTo(v2)) > maxAngle) {
        data.bondSet.clear(i)
      }
    } else if (
      (ap1.atomname === 'OH' && ap1.resname === 'TYR') ||
      (ap2.atomname === 'OH' && ap2.resname === 'TYR')
    ) {
      if (!checkAngle(ap1, ap2, 'OH', 'CZ')) {
        data.bondSet.clear(i)
      }
    }
  }

  return {
    atomSet: data.atomSet,
    bondSet: data.bondSet,
    bondStore: data.bondStore
  }
}

function polarBackboneContacts (structure, maxDistance, maxAngle) {
  maxDistance = maxDistance || 3.5
  maxAngle = maxAngle || 40

  var donorSelection = new Selection(
    '( PROTEIN and .N )'
  )

  var acceptorSelection = new Selection(
    '( PROTEIN and .O )'
  )

  var donorView = structure.getView(donorSelection)
  var acceptorView = structure.getView(acceptorSelection)

  var contact = new Contact(donorView, acceptorView)
  var data = contact.within(maxDistance)
  var bondStore = data.bondStore

  var ap1 = structure.getAtomProxy()
  var ap2 = structure.getAtomProxy()
  var atomCA = structure.getAtomProxy()
  var atomC = structure.getAtomProxy()
  var rp = structure.getResidueProxy()
  var rpPrev = structure.getResidueProxy()
  var v1 = new Vector3()
  var v2 = new Vector3()

  for (var i = 0, il = bondStore.count; i < il; ++i) {
    ap1.index = bondStore.atomIndex1[ i ]
    ap2.index = bondStore.atomIndex2[ i ]

    var atomN, atomO

    if (ap1.atomname === 'N') {
      atomN = ap1
      atomO = ap2
    } else {
      atomN = ap2
      atomO = ap1
    }

    rp.index = atomN.residueIndex

    atomCA.index = rp.getAtomIndexByName('CA')
    if (atomCA.index === undefined) continue

    var prevRes = rp.getPreviousConnectedResidue(rpPrev)
    if (prevRes === undefined) continue

    atomC.index = prevRes.getAtomIndexByName('C')
    if (atomC.index === undefined) continue

    v1.subVectors(atomN, atomC)
    v2.subVectors(atomN, atomCA)
    v1.add(v2).multiplyScalar(0.5)
    v2.subVectors(atomO, atomN)

    // Log.log( radToDeg( v1.angleTo( v2 ) ) );

    if (radToDeg(v1.angleTo(v2)) > maxAngle) {
      data.bondSet.clear(i)
    }
  }

  return {
    atomSet: data.atomSet,
    bondSet: data.bondSet,
    bondStore: data.bondStore
  }
}

export {
  polarContacts,
  polarBackboneContacts
}