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

src/surface/molecular-surface.js

/**
 * @file Molecular Surface
 * @author Alexander Rose <alexander.rose@weirdbyte.de>
 * @private
 */

import { WorkerRegistry } from '../globals.js'
import Worker from '../worker/worker.js'
import EDTSurface from './edt-surface.js'
import { AVSurface } from './av-surface.js'
import Surface from './surface.js'

WorkerRegistry.add('molsurf', function func (e, callback) {
  const a = e.data.args
  const p = e.data.params
  if (a && p) {
    const SurfClass = (p.type === 'av') ? AVSurface : EDTSurface
    const surf = new SurfClass(a.coordList, a.radiusList, a.indexList)
    const sd = surf.getSurface(
            p.type, p.probeRadius, p.scaleFactor, p.cutoff, true, p.smooth, p.contour
        )
    const transferList = [ sd.position.buffer, sd.index.buffer ]
    if (sd.normal) transferList.push(sd.normal.buffer)
    if (sd.atomindex) transferList.push(sd.atomindex.buffer)
    const data = {
      sd: sd,
      p: p
    }
    callback(data, transferList)
  }
}, [ EDTSurface, AVSurface ])

/**
 * Molecular surface parameter object.
 * @typedef {Object} MolecularSurfaceParameters - stage parameters
 * @property {String} type - "av" or "edt"
 * @property {Number} probeRadius - probe radius
 * @property {Number} scaleFactor - higher for better quality
 * @property {Integer} smooth - number of smoothing cycles to apply
 * @property {String} name - name for created surface
 */

/**
 * Create Molecular surfaces
 */
class MolecularSurface {
  constructor (structure) {
    this.structure = structure
  }

  _getAtomData () {
    return this.structure.getAtomData({
      what: { position: true, radius: true, index: true },
      radiusParams: { radius: 'vdw', scale: 1 }
    })
  }

  _makeSurface (sd, p) {
    var surface = new Surface(p.name, '', sd)

    surface.info.type = p.type
    surface.info.probeRadius = p.probeRadius
    surface.info.scaleFactor = p.scaleFactor
    surface.info.smooth = p.smooth
    surface.info.cutoff = p.cutoff

    return surface
  }

    /**
     * Get molecular surface
     * @param {MolecularSurfaceParameters} params - parameters for surface creation
     * @return {Surface} the surface
     */
  getSurface (params) {
    const p = params || {}

    const atomData = this._getAtomData()
    const coordList = atomData.position
    const radiusList = atomData.radius
    const indexList = atomData.index

    const SurfClass = (p.type === 'av') ? AVSurface : EDTSurface
    const surf = new SurfClass(coordList, radiusList, indexList)
    const sd = surf.getSurface(
            p.type, p.probeRadius, p.scaleFactor, p.cutoff, true, p.smooth, p.contour
        )

    return this._makeSurface(sd, p)
  }

    /**
     * Get molecular surface asynchronous
     * @param {MolecularSurfaceParameters} params - parameters for surface creation
     * @param {function(surface: Surface)} callback - function to be called after surface is created
     * @return {undefined}
     */
  getSurfaceWorker (params, callback) {
    const p = Object.assign({}, params)

    if (window.Worker) {
      if (this.worker === undefined) {
        this.worker = new Worker('molsurf')
      }

      const atomData = this._getAtomData()
      const coordList = atomData.position
      const radiusList = atomData.radius
      const indexList = atomData.index

      const msg = {
        args: {
          coordList: coordList,
          radiusList: radiusList,
          indexList: indexList
        },
        params: p
      }

      const transferList = [
        coordList.buffer, radiusList.buffer, indexList.buffer
      ]

      this.worker.post(msg, transferList,

                e => {
                  callback(this._makeSurface(e.data.sd, p))
                },

                e => {
                  console.warn(
                        'MolecularSurface.getSurfaceWorker error - trying without worker', e
                    )
                  this.worker.terminate()
                  this.worker = undefined
                  const surface = this.getSurface(p)
                  callback(surface)
                }

            )
    } else {
      const surface = this.getSurface(p)
      callback(surface)
    }
  }

    /**
     * Cleanup
     * @return {undefined}
     */
  dispose () {
    if (this.worker) this.worker.terminate()
  }
}

export default MolecularSurface