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

src/proxy/bond-proxy.js

/**
 * @file Bond Proxy
 * @author Alexander Rose <alexander.rose@weirdbyte.de>
 * @private
 */

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

/**
 * Bond proxy
 */
class BondProxy {
  /**
   * @param {Structure} structure - the structure
   * @param {Integer} index - the index
   */
  constructor (structure, index) {
    /**
     * @type {Structure}
     */
    this.structure = structure
    /**
     * @type {BondStore}
     */
    this.bondStore = structure.bondStore
    /**
     * @type {Integer}
     */
    this.index = index

    this._v12 = new Vector3()
    this._v13 = new Vector3()
    this._ap1 = this.structure.getAtomProxy()
    this._ap2 = this.structure.getAtomProxy()
    this._ap3 = this.structure.getAtomProxy()
  }

  /**
   * @type {AtomProxy}
   */
  get atom1 () {
    return this.structure.getAtomProxy(this.atomIndex1)
  }

  /**
   * @type {AtomProxy}
   */
  get atom2 () {
    return this.structure.getAtomProxy(this.atomIndex2)
  }

  /**
   * @type {Integer}
   */
  get atomIndex1 () {
    return this.bondStore.atomIndex1[ this.index ]
  }
  set atomIndex1 (value) {
    this.bondStore.atomIndex1[ this.index ] = value
  }

  /**
   * @type {Integer}
   */
  get atomIndex2 () {
    return this.bondStore.atomIndex2[ this.index ]
  }
  set atomIndex2 (value) {
    this.bondStore.atomIndex2[ this.index ] = value
  }

  /**
   * @type {Integer}
   */
  get bondOrder () {
    return this.bondStore.bondOrder[ this.index ]
  }
  set bondOrder (value) {
    this.bondStore.bondOrder[ this.index ] = value
  }

  /**
   * Get reference atom index for the bond
   * @return {Integer|undefined} atom index, or `undefined` if unavailable
   */
  getReferenceAtomIndex () {
    var ap1 = this._ap1
    var ap2 = this._ap2
    ap1.index = this.atomIndex1
    ap2.index = this.atomIndex2
    if (ap1.residueIndex !== ap2.residueIndex) {
      return undefined  // Bond between residues, for now ignore (could detect)
    }
    var typeAtomIndex1 = ap1.index - ap1.residueAtomOffset
    var typeAtomIndex2 = ap2.index - ap2.residueAtomOffset
    var residueType = ap1.residueType
    var ix = residueType.getBondReferenceAtomIndex(typeAtomIndex1, typeAtomIndex2)
    if (ix !== undefined) {
      return ix + ap1.residueAtomOffset
    } else {
      console.warn('No reference atom found', ap1.index, ap2.index)
    }
  }

  /**
   * calculate shift direction for displaying double/triple bonds
   * @param  {Vector3} [v] pre-allocated output vector
   * @return {Vector3} the shift direction vector
   */
  calculateShiftDir (v) {
    if (!v) v = new Vector3()

    var ap1 = this._ap1
    var ap2 = this._ap2
    var ap3 = this._ap3
    var v12 = this._v12
    var v13 = this._v13

    ap1.index = this.atomIndex1
    ap2.index = this.atomIndex2
    var ai3 = this.getReferenceAtomIndex()

    v12.subVectors(ap1, ap2).normalize()
    if (ai3 !== undefined) {
      ap3.index = ai3
      v13.subVectors(ap1, ap3)
    } else {
      v13.copy(ap1)  // no reference point, use origin
    }
    v13.normalize()

    // make sure v13 and v12 are not colinear
    var dp = v12.dot(v13)
    if (1 - Math.abs(dp) < 1e-5) {
      v13.set(1, 0, 0)
      dp = v12.dot(v13)
      if (1 - Math.abs(dp) < 1e-5) {
        v13.set(0, 1, 0)
        dp = v12.dot(v13)
      }
    }

    return v.copy(v13.sub(v12.multiplyScalar(dp))).normalize()
  }

  qualifiedName () {
    return this.atomIndex1 + '=' + this.atomIndex2
  }

  /**
   * Clone object
   * @return {BondProxy} cloned bond
   */
  clone () {
    return new this.constructor(this.structure, this.index)
  }

  toObject () {
    return {
      atomIndex1: this.atomIndex1,
      atomIndex2: this.atomIndex2,
      bondOrder: this.bondOrder
    }
  }
}

export default BondProxy