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

src/geometry/primitive.js

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

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

import { BufferRegistry, PickerRegistry } from '../globals.js'

function addElement (elm, array) {
  if (elm.toArray !== undefined) {
    elm = elm.toArray()
  } else if (elm.x !== undefined) {
    elm = [ elm.x, elm.y, elm.z ]
  } else if (elm.r !== undefined) {
    elm = [ elm.r, elm.g, elm.b ]
  }
  array.push.apply(array, elm)
}

const tmpVec = new Vector3()

/**
 * Base class for geometry primitives
 * @interface
 */
class Primitive {
  static get Picker () { return PickerRegistry.get(this.type) }
  static get Buffer () { return BufferRegistry.get(this.type) }

  static getShapeKey (name) {
    return this.type + name[0].toUpperCase() + name.substr(1)
  }

  static valueToShape (shape, name, value) {
    const data = shape[this.getShapeKey(name)]
    const type = this.fields[name]

    switch (type) {
      case 'v3':
      case 'c':
        addElement(value, data)
        break
      default:
        data.push(value)
    }
  }

  static objectToShape (shape, data) {
    Object.keys(this.fields).forEach(name => {
      this.valueToShape(shape, name, data[name])
    })
    this.valueToShape(shape, 'name', data.name)
    this.expandBoundingBox(shape.boundingBox, data)
  }

  static valueFromShape (shape, pid, name) {
    const data = shape[this.getShapeKey(name)]
    const type = this.fields[name]

    switch (type) {
      case 'v3':
        return new Vector3().fromArray(data, 3 * pid)
      case 'c':
        return new Color().fromArray(data, 3 * pid)
      default:
        return data[pid]
    }
  }

  static objectFromShape (shape, pid) {
    const o = {
      shape,
      name: this.valueFromShape(shape, pid, 'name')
    }

    Object.keys(this.fields).forEach(name => {
      o[name] = this.valueFromShape(shape, pid, name)
    })

    return o
  }

  static arrayFromShape (shape, name) {
    const data = shape[this.getShapeKey(name)]
    const type = this.fields[name]

    switch (type) {
      case 's':
        return data
      default:
        return new Float32Array(data)
    }
  }

  static dataFromShape (shape) {
    const data = {}

    if (this.Picker) {
      data.picking = new this.Picker(shape)
    }

    Object.keys(this.fields).forEach(name => {
      data[name] = this.arrayFromShape(shape, name)
    })

    return data
  }

  static bufferFromShape (shape, params) {
    return new this.Buffer(this.dataFromShape(shape), params)
  }
}

/**
 * Sphere geometry primitive
 */
class SpherePrimitive extends Primitive {
  static get type () { return 'sphere' }

  static get fields () {
    return {
      position: 'v3',
      color: 'c',
      radius: 'f'
    }
  }

  static positionFromShape (shape, pid) {
    return this.valueFromShape(shape, pid, 'position')
  }

  static expandBoundingBox (box, data) {
    box.expandByPoint(tmpVec.fromArray(data.position))
  }
}

/**
 * Box geometry primitive
 */
class BoxPrimitive extends SpherePrimitive {
  static get type () { return 'box' }

  static get fields () {
    return {
      position: 'v3',
      color: 'c',
      size: 'f',
      heightAxis: 'v3',
      depthAxis: 'v3'
    }
  }
}

/**
 * Octahedron geometry primitive
 */
class OctahedronPrimitive extends BoxPrimitive {
  static get type () { return 'octahedron' }
}

/**
 * Tetrahedron geometry primitive
 */
class TetrahedronPrimitive extends BoxPrimitive {
  static get type () { return 'tetrahedron' }
}

/**
 * Cylinder geometry primitive
 */
class CylinderPrimitive extends Primitive {
  static get type () { return 'cylinder' }

  static get fields () {
    return {
      position1: 'v3',
      position2: 'v3',
      color: 'c',
      radius: 'f'
    }
  }

  static positionFromShape (shape, pid) {
    const p1 = this.valueFromShape(shape, pid, 'position1')
    const p2 = this.valueFromShape(shape, pid, 'position2')
    return p1.add(p2).multiplyScalar(0.5)
  }

  static expandBoundingBox (box, data) {
    box.expandByPoint(tmpVec.fromArray(data.position1))
    box.expandByPoint(tmpVec.fromArray(data.position2))
  }
}

/**
 * Arrow geometry primitive
 */
class ArrowPrimitive extends CylinderPrimitive {
  static get type () { return 'arrow' }
}

/**
 * Cone geometry primitive
 */
class ConePrimitive extends CylinderPrimitive {
  static get type () { return 'cone' }
}

/**
 * Ellipsoid geometry primitive
 */
class EllipsoidPrimitive extends SpherePrimitive {
  static get type () { return 'ellipsoid' }

  static get fields () {
    return {
      position: 'v3',
      color: 'c',
      radius: 'f',
      majorAxis: 'v3',
      minorAxis: 'v3'
    }
  }
}

/**
 * Torus geometry primitive
 */
class TorusPrimitive extends EllipsoidPrimitive {
  static get type () { return 'torus' }
}

/**
 * Text geometry primitive
 */
class TextPrimitive extends SpherePrimitive {
  static get type () { return 'text' }

  static get fields () {
    return {
      position: 'v3',
      color: 'c',
      size: 'f',
      text: 's'
    }
  }
}

export {
  ArrowPrimitive,
  BoxPrimitive,
  ConePrimitive,
  CylinderPrimitive,
  EllipsoidPrimitive,
  OctahedronPrimitive,
  SpherePrimitive,
  TetrahedronPrimitive,
  TextPrimitive,
  TorusPrimitive
}