text: const vec3 = require('../maths/vec3')
  
  const geom3 = require('../geometries/geom3')
  const poly3 = require('../geometries/poly3')
  
  const { isGTE, isNumberArray } = require('./commonChecks')
  
  /**
   * Construct an axis-aligned ellipsoid in three dimensional space.
   * @param {Object} [options] - options for construction
   * @param {Array} [options.center=[0,0,0]] - center of ellipsoid
   * @param {Array} [options.radius=[1,1,1]] - radius of ellipsoid, along X, Y and Z
   * @param {Number} [options.segments=32] - number of segements to create per full rotation
   * @param {Array} [options.axes] -  an array with three vectors for the x, y and z base vectors
   * @returns {geom3} new 3D geometry
   * @alias module:modeling/primitives.ellipsoid
   *
   * @example
   * let myshape = ellipsoid({radius: [5, 10, 20]})
  */
  const ellipsoid = (options) => {
    const defaults = {
      center: [0, 0, 0],
      radius: [1, 1, 1],
      segments: 32,
      axes: [[1, 0, 0], [0, -1, 0], [0, 0, 1]]
    }
    const { center, radius, segments, axes } = Object.assign({}, defaults, options)
  
    if (!isNumberArray(center, 3)) throw new Error('center must be an array of X, Y and Z values')
    if (!isNumberArray(radius, 3)) throw new Error('radius must be an array of X, Y and Z values')
    if (!radius.every((n) => n > 0)) throw new Error('radius values must be greater than zero')
    if (!isGTE(segments, 4)) throw new Error('segments must be four or more')
  
    const xvector = vec3.scale(vec3.create(), vec3.unit(vec3.create(), axes[0]), radius[0])
    const yvector = vec3.scale(vec3.create(), vec3.unit(vec3.create(), axes[1]), radius[1])
    const zvector = vec3.scale(vec3.create(), vec3.unit(vec3.create(), axes[2]), radius[2])
  
    const qsegments = Math.round(segments / 4)
    let prevcylinderpoint
    const polygons = []
    const p1 = vec3.create()
    const p2 = vec3.create()
    for (let slice1 = 0; slice1 <= segments; slice1++) {
      const angle = Math.PI * 2.0 * slice1 / segments
      const cylinderpoint = vec3.add(vec3.create(), vec3.scale(p1, xvector, Math.cos(angle)), vec3.scale(p2, yvector, Math.sin(angle)))
      if (slice1 > 0) {
        let prevcospitch, prevsinpitch
        for (let slice2 = 0; slice2 <= qsegments; slice2++) {
          const pitch = 0.5 * Math.PI * slice2 / qsegments
          const cospitch = Math.cos(pitch)
          const sinpitch = Math.sin(pitch)
          if (slice2 > 0) {
            let points = []
            let point
            point = vec3.subtract(vec3.create(), vec3.scale(p1, prevcylinderpoint, prevcospitch), vec3.scale(p2, zvector, prevsinpitch))
            points.push(vec3.add(point, point, center))
            point = vec3.subtract(vec3.create(), vec3.scale(p1, cylinderpoint, prevcospitch), vec3.scale(p2, zvector, prevsinpitch))
            points.push(vec3.add(point, point, center))
            if (slice2 < qsegments) {
              point = vec3.subtract(vec3.create(), vec3.scale(p1, cylinderpoint, cospitch), vec3.scale(p2, zvector, sinpitch))
              points.push(vec3.add(point, point, center))
            }
            point = vec3.subtract(vec3.create(), vec3.scale(p1, prevcylinderpoint, cospitch), vec3.scale(p2, zvector, sinpitch))
            points.push(vec3.add(point, point, center))
  
            polygons.push(poly3.fromPoints(points))
  
            points = []
            point = vec3.add(vec3.create(), vec3.scale(p1, prevcylinderpoint, prevcospitch), vec3.scale(p2, zvector, prevsinpitch))
            points.push(vec3.add(vec3.create(), center, point))
            point = vec3.add(point, vec3.scale(p1, cylinderpoint, prevcospitch), vec3.scale(p2, zvector, prevsinpitch))
            points.push(vec3.add(vec3.create(), center, point))
            if (slice2 < qsegments) {
              point = vec3.add(point, vec3.scale(p1, cylinderpoint, cospitch), vec3.scale(p2, zvector, sinpitch))
              points.push(vec3.add(vec3.create(), center, point))
            }
            point = vec3.add(point, vec3.scale(p1, prevcylinderpoint, cospitch), vec3.scale(p2, zvector, sinpitch))
            points.push(vec3.add(vec3.create(), center, point))
            points.reverse()
  
            polygons.push(poly3.fromPoints(points))
          }
          prevcospitch = cospitch
          prevsinpitch = sinpitch
        }
      }
      prevcylinderpoint = cylinderpoint
    }
    return geom3.create(polygons)
  }
  
  module.exports = ellipsoid
  