KochSnowflakeBuilder.js 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. import CoordinateList from '../../geom/CoordinateList'
  2. import Coordinate from '../../geom/Coordinate'
  3. import Vector2D from '../../math/Vector2D'
  4. import GeometricShapeBuilder from '../GeometricShapeBuilder'
  5. export default class KochSnowflakeBuilder extends GeometricShapeBuilder {
  6. constructor() {
  7. super()
  8. KochSnowflakeBuilder.constructor_.apply(this, arguments)
  9. }
  10. static constructor_() {
  11. this._coordList = new CoordinateList()
  12. const geomFactory = arguments[0]
  13. GeometricShapeBuilder.constructor_.call(this, geomFactory)
  14. }
  15. static recursionLevelForSize(numPts) {
  16. const pow4 = Math.trunc(numPts / 3)
  17. const exp = Math.log(pow4) / Math.log(4)
  18. return Math.trunc(exp)
  19. }
  20. getBoundary(level, origin, width) {
  21. let y = origin.y
  22. if (level > 0)
  23. y += KochSnowflakeBuilder.THIRD_HEIGHT * width
  24. const p0 = new Coordinate(origin.x, y)
  25. const p1 = new Coordinate(origin.x + width / 2, y + width * KochSnowflakeBuilder.HEIGHT_FACTOR)
  26. const p2 = new Coordinate(origin.x + width, y)
  27. this.addSide(level, p0, p1)
  28. this.addSide(level, p1, p2)
  29. this.addSide(level, p2, p0)
  30. this._coordList.closeRing()
  31. return this._coordList.toCoordinateArray()
  32. }
  33. getGeometry() {
  34. const level = KochSnowflakeBuilder.recursionLevelForSize(this._numPts)
  35. const baseLine = this.getSquareBaseLine()
  36. const pts = this.getBoundary(level, baseLine.getCoordinate(0), baseLine.getLength())
  37. return this._geomFactory.createPolygon(this._geomFactory.createLinearRing(pts), null)
  38. }
  39. addSegment(p0, p1) {
  40. this._coordList.add(p1)
  41. }
  42. addSide(level, p0, p1) {
  43. if (level === 0) {
  44. this.addSegment(p0, p1)
  45. } else {
  46. const base = Vector2D.create(p0, p1)
  47. const midPt = base.multiply(0.5).translate(p0)
  48. const heightVec = base.multiply(KochSnowflakeBuilder.THIRD_HEIGHT)
  49. const offsetVec = heightVec.rotateByQuarterCircle(1)
  50. const offsetPt = offsetVec.translate(midPt)
  51. const n2 = level - 1
  52. const thirdPt = base.multiply(KochSnowflakeBuilder.ONE_THIRD).translate(p0)
  53. const twoThirdPt = base.multiply(KochSnowflakeBuilder.TWO_THIRDS).translate(p0)
  54. this.addSide(n2, p0, thirdPt)
  55. this.addSide(n2, thirdPt, offsetPt)
  56. this.addSide(n2, offsetPt, twoThirdPt)
  57. this.addSide(n2, twoThirdPt, p1)
  58. }
  59. }
  60. }
  61. KochSnowflakeBuilder.HEIGHT_FACTOR = Math.sin(Math.PI / 3.0)
  62. KochSnowflakeBuilder.ONE_THIRD = 1.0 / 3.0
  63. KochSnowflakeBuilder.THIRD_HEIGHT = KochSnowflakeBuilder.HEIGHT_FACTOR / 3.0
  64. KochSnowflakeBuilder.TWO_THIRDS = 2.0 / 3.0