modeling/src/primitives/polyhedron.js

  1. const geom3 = require('../geometries/geom3')
  2. const poly3 = require('../geometries/poly3')
  3. const { isNumberArray } = require('./commonChecks')
  4. /**
  5. * Construct a polyhedron in three dimensional space from the given set of 3D points and faces.
  6. *
  7. * The faces can define outward or inward facing polygons (orientation).
  8. * However, each face must define a counter clockwise rotation of points which follows the right hand rule.
  9. * @param {Object} options - options for construction
  10. * @param {Array} options.points - list of points in 3D space
  11. * @param {Array} options.faces - list of faces, where each face is a set of indexes into the points
  12. * @param {Array} [options.colors=undefined] - list of RGBA colors to apply to each face
  13. * @param {String} [options.orientation='outward'] - orientation of faces
  14. * @returns {geom3} new 3D geometry
  15. * @alias module:modeling/primitives.polyhedron
  16. *
  17. * @example
  18. * let mypoints = [ [10, 10, 0], [10, -10, 0], [-10, -10, 0], [-10, 10, 0], [0, 0, 10] ]
  19. * let myfaces = [ [0, 1, 4], [1, 2, 4], [2, 3, 4], [3, 0, 4], [1, 0, 3], [2, 1, 3] ]
  20. * let myshape = polyhedron({points: mypoints, faces: myfaces, orientation: 'inward'})
  21. */
  22. const polyhedron = (options) => {
  23. const defaults = {
  24. points: [],
  25. faces: [],
  26. colors: undefined,
  27. orientation: 'outward'
  28. }
  29. const { points, faces, colors, orientation } = Object.assign({}, defaults, options)
  30. if (!(Array.isArray(points) && Array.isArray(faces))) {
  31. throw new Error('points and faces must be arrays')
  32. }
  33. if (points.length < 3) {
  34. throw new Error('three or more points are required')
  35. }
  36. if (faces.length < 1) {
  37. throw new Error('one or more faces are required')
  38. }
  39. if (colors) {
  40. if (!Array.isArray(colors)) {
  41. throw new Error('colors must be an array')
  42. }
  43. if (colors.length !== faces.length) {
  44. throw new Error('faces and colors must have the same length')
  45. }
  46. }
  47. points.forEach((point, i) => {
  48. if (!isNumberArray(point, 3)) throw new Error(`point ${i} must be an array of X, Y, Z values`)
  49. })
  50. faces.forEach((face, i) => {
  51. if (face.length < 3) throw new Error(`face ${i} must contain 3 or more indexes`)
  52. if (!isNumberArray(face, face.length)) throw new Error(`face ${i} must be an array of numbers`)
  53. })
  54. // invert the faces if orientation is inwards, as all internals expect outwarding facing polygons
  55. if (orientation !== 'outward') {
  56. faces.forEach((face) => face.reverse())
  57. }
  58. const polygons = faces.map((face, findex) => {
  59. const polygon = poly3.create(face.map((pindex) => points[pindex]))
  60. if (colors && colors[findex]) polygon.color = colors[findex]
  61. return polygon
  62. })
  63. return geom3.create(polygons)
  64. }
  65. module.exports = polyhedron