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

src/representation/dot-representation.js

/**
 * @file Dot Representation
 * @author Alexander Rose <alexander.rose@weirdbyte.de>
 * @private
 */

import { ExtensionFragDepth } from '../globals.js'
import { defaults } from '../utils.js'
import Representation from './representation.js'
import Volume from '../surface/volume.js'
import FilteredVolume from '../surface/filtered-volume.js'
import SphereBuffer from '../buffer/sphere-buffer.js'
import PointBuffer from '../buffer/point-buffer.js'

/**
 * Dot representation parameter object. Extends {@link RepresentationParameters}
 *
 * @typedef {Object} DotRepresentationParameters - dot representation parameters
 *
 * @property {String} thresholdType - Meaning of the threshold values. Either *value* for the literal value or *sigma* as a factor of the sigma of the data. For volume data only.
 * @property {Number} thresholdMin - Minimum value to be displayed. For volume data only.
 * @property {Number} thresholdMax - Maximum value to be displayed. For volume data only.
 * @property {Number} thresholdOut - Show only values falling outside of the treshold minumum and maximum. For volume data only.
 */

/**
 * Dot representation
 */
class DotRepresentation extends Representation {
  /**
   * Create Dot representation object
   * @param {Surface|Volume} surface - the surface or volume to be represented
   * @param {Viewer} viewer - a viewer object
   * @param {DotRepresentationParameters} params - dot representation parameters
   */
  constructor (surface, viewer, params) {
    super(surface, viewer, params)

    this.type = 'dot'

    this.parameters = Object.assign({

      thresholdType: {
        type: 'select',
        rebuild: true,
        options: {
          'value': 'value', 'sigma': 'sigma'
        }
      },
      thresholdMin: {
        type: 'number', precision: 3, max: Infinity, min: -Infinity, rebuild: true
      },
      thresholdMax: {
        type: 'number', precision: 3, max: Infinity, min: -Infinity, rebuild: true
      },
      thresholdOut: {
        type: 'boolean', rebuild: true
      },
      dotType: {
        type: 'select',
        rebuild: true,
        options: {
          '': '',
          'sphere': 'sphere',
          'point': 'point'
        }
      },
      radiusType: {
        type: 'select',
        options: {
          '': '',
          'value': 'value',
          'abs-value': 'abs-value',
          'value-min': 'value-min',
          'deviation': 'deviation',
          'size': 'size'
        }
      },
      radius: {
        type: 'number', precision: 3, max: 10.0, min: 0.001, property: 'size'
      },
      scale: {
        type: 'number', precision: 3, max: 10.0, min: 0.001
      },
      sphereDetail: true,
      disableImpostor: true,

      pointSize: {
        type: 'number', precision: 1, max: 100, min: 0, buffer: true
      },
      sizeAttenuation: {
        type: 'boolean', buffer: true
      },
      sortParticles: {
        type: 'boolean', rebuild: true
      },
      useTexture: {
        type: 'boolean', buffer: true
      },
      alphaTest: {
        type: 'range', step: 0.001, max: 1, min: 0, buffer: true
      },
      forceTransparent: {
        type: 'boolean', buffer: true
      },
      edgeBleach: {
        type: 'range', step: 0.001, max: 1, min: 0, buffer: true
      }

    }, this.parameters, {

      colorScheme: {
        type: 'select',
        update: 'color',
        options: {
          '': '',
          'value': 'value',
          'uniform': 'uniform',
          'random': 'random'
        }
      }

    })

    if (surface instanceof Volume) {
      this.surface = undefined
      this.volume = new FilteredVolume(surface)
    } else {
      this.surface = surface
      this.volume = undefined
    }

    this.init(params)
  }

  init (params) {
    var p = params || {}
    p.colorScheme = defaults(p.colorScheme, 'uniform')
    p.colorValue = defaults(p.colorValue, 0xDDDDDD)

    this.thresholdType = defaults(p.thresholdType, 'sigma')
    this.thresholdMin = defaults(p.thresholdMin, 2.0)
    this.thresholdMax = defaults(p.thresholdMax, Infinity)
    this.thresholdOut = defaults(p.thresholdOut, false)
    this.dotType = defaults(p.dotType, 'point')
    this.radius = defaults(p.radius, 0.1)
    this.scale = defaults(p.scale, 1.0)

    this.pointSize = defaults(p.pointSize, 1)
    this.sizeAttenuation = defaults(p.sizeAttenuation, true)
    this.sortParticles = defaults(p.sortParticles, false)
    this.useTexture = defaults(p.useTexture, false)
    this.alphaTest = defaults(p.alphaTest, 0.5)
    this.forceTransparent = defaults(p.forceTransparent, false)
    this.edgeBleach = defaults(p.edgeBleach, 0.0)

    super.init(p)

    this.build()
  }

  attach (callback) {
    this.bufferList.forEach(buffer => {
      this.viewer.add(buffer)
    })
    this.setVisibility(this.visible)

    callback()
  }

  create () {
    var dotData = {}

    if (this.volume) {
      var volume = this.volume
      var thresholdMin, thresholdMax

      if (this.thresholdType === 'sigma') {
        thresholdMin = volume.getValueForSigma(this.thresholdMin)
        thresholdMax = volume.getValueForSigma(this.thresholdMax)
      } else {
        thresholdMin = this.thresholdMin
        thresholdMax = this.thresholdMax
      }
      volume.setFilter(thresholdMin, thresholdMax, this.thresholdOut)

      dotData.position = volume.getDataPosition()
      dotData.color = volume.getDataColor(this.getColorParams())
      if (this.dotType === 'sphere') {
        dotData.radius = volume.getDataSize(this.radius, this.scale)
        dotData.picking = volume.getDataPicking()
      }
    } else {
      var surface = this.surface
      dotData.position = surface.getPosition()
      dotData.color = surface.getColor(this.getColorParams())
      if (this.dotType === 'sphere') {
        dotData.radius = surface.getSize(this.radius, this.scale)
        dotData.picking = surface.getPicking()
      }
    }

    if (this.dotType === 'sphere') {
      this.dotBuffer = new SphereBuffer(
        dotData,
        this.getBufferParams({
          sphereDetail: this.sphereDetail,
          disableImpostor: this.disableImpostor,
          dullInterior: false
        })
      )
    } else {
      this.dotBuffer = new PointBuffer(
        dotData,
        this.getBufferParams({
          pointSize: this.pointSize,
          sizeAttenuation: this.sizeAttenuation,
          sortParticles: this.sortParticles,
          useTexture: this.useTexture,
          alphaTest: this.alphaTest,
          forceTransparent: this.forceTransparent,
          edgeBleach: this.edgeBleach
        })
      )
    }

    this.bufferList.push(this.dotBuffer)
  }

  update (what) {
    if (this.bufferList.length === 0) return

    what = what || {}

    var dotData = {}

    if (what.color) {
      if (this.volume) {
        dotData.color = this.volume.getDataColor(
          this.getColorParams()
        )
      } else {
        dotData.color = this.surface.getColor(
          this.getColorParams()
        )
      }
    }

    if (this.dotType === 'sphere' && (what.radius || what.scale)) {
      if (this.volume) {
        dotData.radius = this.volume.getDataSize(
          this.radius, this.scale
        )
      } else {
        dotData.radius = this.surface.getSize(
          this.radius, this.scale
        )
      }
    }

    this.dotBuffer.setAttributes(dotData)
  }

  setParameters (params, what, rebuild) {
    what = what || {}

    if (params && params.thresholdType !== undefined &&
        this.volume instanceof Volume
    ) {
      if (this.thresholdType === 'value' &&
          params.thresholdType === 'sigma'
      ) {
        this.thresholdMin = this.volume.getSigmaForValue(
          this.thresholdMin
        )
        this.thresholdMax = this.volume.getSigmaForValue(
          this.thresholdMax
        )
      } else if (this.thresholdType === 'sigma' &&
                 params.thresholdType === 'value'
      ) {
        this.thresholdMin = this.volume.getValueForSigma(
          this.thresholdMin
        )
        this.thresholdMax = this.volume.getValueForSigma(
          this.thresholdMax
        )
      }

      this.thresholdType = params.thresholdType
    }

    if (params && params.radiusType !== undefined) {
      if (params.radiusType === 'radius') {
        this.radius = 0.1
      } else {
        this.radius = params.radiusType
      }
      what.radius = true
      if (this.dotType === 'sphere' &&
          (!ExtensionFragDepth || this.disableImpostor)
      ) {
        rebuild = true
      }
    }

    if (params && params.radius !== undefined) {
      what.radius = true
      if (this.dotType === 'sphere' &&
          (!ExtensionFragDepth || this.disableImpostor)
      ) {
        rebuild = true
      }
    }

    if (params && params.scale !== undefined) {
      what.scale = true
      if (this.dotType === 'sphere' &&
          (!ExtensionFragDepth || this.disableImpostor)
      ) {
        rebuild = true
      }
    }

    super.setParameters(params, what, rebuild)

    return this
  }
}

export default DotRepresentation