modeling/src/primitives/torus.js

  1. const { TAU } = require('../maths/constants')
  2. const extrudeRotate = require('../operations/extrusions/extrudeRotate')
  3. const { rotate } = require('../operations/transforms/rotate')
  4. const { translate } = require('../operations/transforms/translate')
  5. const circle = require('./circle')
  6. const { isGT, isGTE } = require('./commonChecks')
  7. /**
  8. * Construct a torus by revolving a small circle (inner) about the circumference of a large (outer) circle.
  9. * @param {Object} [options] - options for construction
  10. * @param {Number} [options.innerRadius=1] - radius of small (inner) circle
  11. * @param {Number} [options.outerRadius=4] - radius of large (outer) circle
  12. * @param {Integer} [options.innerSegments=32] - number of segments to create per rotation
  13. * @param {Integer} [options.outerSegments=32] - number of segments to create per rotation
  14. * @param {Integer} [options.innerRotation=0] - rotation of small (inner) circle in radians
  15. * @param {Number} [options.outerRotation=TAU] - rotation (outer) of the torus (RADIANS)
  16. * @param {Number} [options.startAngle=0] - start angle of the torus (RADIANS)
  17. * @returns {geom3} new 3D geometry
  18. * @alias module:modeling/primitives.torus
  19. *
  20. * @example
  21. * let myshape = torus({ innerRadius: 10, outerRadius: 100 })
  22. */
  23. const torus = (options) => {
  24. const defaults = {
  25. innerRadius: 1,
  26. innerSegments: 32,
  27. outerRadius: 4,
  28. outerSegments: 32,
  29. innerRotation: 0,
  30. startAngle: 0,
  31. outerRotation: TAU
  32. }
  33. const { innerRadius, innerSegments, outerRadius, outerSegments, innerRotation, startAngle, outerRotation } = Object.assign({}, defaults, options)
  34. if (!isGT(innerRadius, 0)) throw new Error('innerRadius must be greater than zero')
  35. if (!isGTE(innerSegments, 3)) throw new Error('innerSegments must be three or more')
  36. if (!isGT(outerRadius, 0)) throw new Error('outerRadius must be greater than zero')
  37. if (!isGTE(outerSegments, 3)) throw new Error('outerSegments must be three or more')
  38. if (!isGTE(startAngle, 0)) throw new Error('startAngle must be positive')
  39. if (!isGT(outerRotation, 0)) throw new Error('outerRotation must be greater than zero')
  40. if (innerRadius >= outerRadius) throw new Error('inner circle is too large to rotate about the outer circle')
  41. let innerCircle = circle({ radius: innerRadius, segments: innerSegments })
  42. if (innerRotation !== 0) {
  43. innerCircle = rotate([0, 0, innerRotation], innerCircle)
  44. }
  45. innerCircle = translate([outerRadius, 0], innerCircle)
  46. const extrudeOptions = {
  47. startAngle: startAngle,
  48. angle: outerRotation,
  49. segments: outerSegments
  50. }
  51. return extrudeRotate(extrudeOptions, innerCircle)
  52. }
  53. module.exports = torus