GeometricShapeFactory.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. import GeometryFactory from '../geom/GeometryFactory'
  2. import Coordinate from '../geom/Coordinate'
  3. import AffineTransformation from '../geom/util/AffineTransformation'
  4. import Envelope from '../geom/Envelope'
  5. export default class GeometricShapeFactory {
  6. constructor() {
  7. GeometricShapeFactory.constructor_.apply(this, arguments)
  8. }
  9. static constructor_() {
  10. this._geomFact = null
  11. this._precModel = null
  12. this._dim = new Dimensions()
  13. this._nPts = 100
  14. this._rotationAngle = 0.0
  15. if (arguments.length === 0) {
  16. GeometricShapeFactory.constructor_.call(this, new GeometryFactory())
  17. } else if (arguments.length === 1) {
  18. const geomFact = arguments[0]
  19. this._geomFact = geomFact
  20. this._precModel = geomFact.getPrecisionModel()
  21. }
  22. }
  23. createSupercircle(power) {
  24. const recipPow = 1.0 / power
  25. const radius = this._dim.getMinSize() / 2
  26. const centre = this._dim.getCentre()
  27. const r4 = Math.pow(radius, power)
  28. const y0 = radius
  29. const xyInt = Math.pow(r4 / 2, recipPow)
  30. const nSegsInOct = Math.trunc(this._nPts / 8)
  31. const totPts = nSegsInOct * 8 + 1
  32. const pts = new Array(totPts).fill(null)
  33. const xInc = xyInt / nSegsInOct
  34. for (let i = 0; i <= nSegsInOct; i++) {
  35. let x = 0.0
  36. let y = y0
  37. if (i !== 0) {
  38. x = xInc * i
  39. const x4 = Math.pow(x, power)
  40. y = Math.pow(r4 - x4, recipPow)
  41. }
  42. pts[i] = this.coordTrans(x, y, centre)
  43. pts[2 * nSegsInOct - i] = this.coordTrans(y, x, centre)
  44. pts[2 * nSegsInOct + i] = this.coordTrans(y, -x, centre)
  45. pts[4 * nSegsInOct - i] = this.coordTrans(x, -y, centre)
  46. pts[4 * nSegsInOct + i] = this.coordTrans(-x, -y, centre)
  47. pts[6 * nSegsInOct - i] = this.coordTrans(-y, -x, centre)
  48. pts[6 * nSegsInOct + i] = this.coordTrans(-y, x, centre)
  49. pts[8 * nSegsInOct - i] = this.coordTrans(-x, y, centre)
  50. }
  51. pts[pts.length - 1] = new Coordinate(pts[0])
  52. const ring = this._geomFact.createLinearRing(pts)
  53. const poly = this._geomFact.createPolygon(ring)
  54. return this.rotate(poly)
  55. }
  56. setNumPoints(nPts) {
  57. this._nPts = nPts
  58. }
  59. setBase(base) {
  60. this._dim.setBase(base)
  61. }
  62. setRotation(radians) {
  63. this._rotationAngle = radians
  64. }
  65. setWidth(width) {
  66. this._dim.setWidth(width)
  67. }
  68. createEllipse() {
  69. const env = this._dim.getEnvelope()
  70. const xRadius = env.getWidth() / 2.0
  71. const yRadius = env.getHeight() / 2.0
  72. const centreX = env.getMinX() + xRadius
  73. const centreY = env.getMinY() + yRadius
  74. const pts = new Array(this._nPts + 1).fill(null)
  75. let iPt = 0
  76. for (let i = 0; i < this._nPts; i++) {
  77. const ang = i * (2 * Math.PI / this._nPts)
  78. const x = xRadius * Math.cos(ang) + centreX
  79. const y = yRadius * Math.sin(ang) + centreY
  80. pts[iPt++] = this.coord(x, y)
  81. }
  82. pts[iPt] = new Coordinate(pts[0])
  83. const ring = this._geomFact.createLinearRing(pts)
  84. const poly = this._geomFact.createPolygon(ring)
  85. return this.rotate(poly)
  86. }
  87. coordTrans(x, y, trans) {
  88. return this.coord(x + trans.x, y + trans.y)
  89. }
  90. createSquircle() {
  91. return this.createSupercircle(4)
  92. }
  93. setEnvelope(env) {
  94. this._dim.setEnvelope(env)
  95. }
  96. setCentre(centre) {
  97. this._dim.setCentre(centre)
  98. }
  99. createArc(startAng, angExtent) {
  100. const env = this._dim.getEnvelope()
  101. const xRadius = env.getWidth() / 2.0
  102. const yRadius = env.getHeight() / 2.0
  103. const centreX = env.getMinX() + xRadius
  104. const centreY = env.getMinY() + yRadius
  105. let angSize = angExtent
  106. if (angSize <= 0.0 || angSize > 2 * Math.PI) angSize = 2 * Math.PI
  107. const angInc = angSize / (this._nPts - 1)
  108. const pts = new Array(this._nPts).fill(null)
  109. let iPt = 0
  110. for (let i = 0; i < this._nPts; i++) {
  111. const ang = startAng + i * angInc
  112. const x = xRadius * Math.cos(ang) + centreX
  113. const y = yRadius * Math.sin(ang) + centreY
  114. pts[iPt++] = this.coord(x, y)
  115. }
  116. const line = this._geomFact.createLineString(pts)
  117. return this.rotate(line)
  118. }
  119. rotate(geom) {
  120. if (this._rotationAngle !== 0.0) {
  121. const trans = AffineTransformation.rotationInstance(this._rotationAngle, this._dim.getCentre().x, this._dim.getCentre().y)
  122. geom.apply(trans)
  123. }
  124. return geom
  125. }
  126. coord(x, y) {
  127. const pt = new Coordinate(x, y)
  128. this._precModel.makePrecise(pt)
  129. return pt
  130. }
  131. createArcPolygon(startAng, angExtent) {
  132. const env = this._dim.getEnvelope()
  133. const xRadius = env.getWidth() / 2.0
  134. const yRadius = env.getHeight() / 2.0
  135. const centreX = env.getMinX() + xRadius
  136. const centreY = env.getMinY() + yRadius
  137. let angSize = angExtent
  138. if (angSize <= 0.0 || angSize > 2 * Math.PI) angSize = 2 * Math.PI
  139. const angInc = angSize / (this._nPts - 1)
  140. const pts = new Array(this._nPts + 2).fill(null)
  141. let iPt = 0
  142. pts[iPt++] = this.coord(centreX, centreY)
  143. for (let i = 0; i < this._nPts; i++) {
  144. const ang = startAng + angInc * i
  145. const x = xRadius * Math.cos(ang) + centreX
  146. const y = yRadius * Math.sin(ang) + centreY
  147. pts[iPt++] = this.coord(x, y)
  148. }
  149. pts[iPt++] = this.coord(centreX, centreY)
  150. const ring = this._geomFact.createLinearRing(pts)
  151. const poly = this._geomFact.createPolygon(ring)
  152. return this.rotate(poly)
  153. }
  154. createRectangle() {
  155. let i = null
  156. let ipt = 0
  157. let nSide = Math.trunc(this._nPts / 4)
  158. if (nSide < 1) nSide = 1
  159. const XsegLen = this._dim.getEnvelope().getWidth() / nSide
  160. const YsegLen = this._dim.getEnvelope().getHeight() / nSide
  161. const pts = new Array(4 * nSide + 1).fill(null)
  162. const env = this._dim.getEnvelope()
  163. for ((i = 0); i < nSide; i++) {
  164. const x = env.getMinX() + i * XsegLen
  165. const y = env.getMinY()
  166. pts[ipt++] = this.coord(x, y)
  167. }
  168. for ((i = 0); i < nSide; i++) {
  169. const x = env.getMaxX()
  170. const y = env.getMinY() + i * YsegLen
  171. pts[ipt++] = this.coord(x, y)
  172. }
  173. for ((i = 0); i < nSide; i++) {
  174. const x = env.getMaxX() - i * XsegLen
  175. const y = env.getMaxY()
  176. pts[ipt++] = this.coord(x, y)
  177. }
  178. for ((i = 0); i < nSide; i++) {
  179. const x = env.getMinX()
  180. const y = env.getMaxY() - i * YsegLen
  181. pts[ipt++] = this.coord(x, y)
  182. }
  183. pts[ipt++] = new Coordinate(pts[0])
  184. const ring = this._geomFact.createLinearRing(pts)
  185. const poly = this._geomFact.createPolygon(ring)
  186. return this.rotate(poly)
  187. }
  188. createCircle() {
  189. return this.createEllipse()
  190. }
  191. setHeight(height) {
  192. this._dim.setHeight(height)
  193. }
  194. setSize(size) {
  195. this._dim.setSize(size)
  196. }
  197. }
  198. class Dimensions {
  199. constructor() {
  200. Dimensions.constructor_.apply(this, arguments)
  201. }
  202. static constructor_() {
  203. this.base = null
  204. this.centre = null
  205. this.width = null
  206. this.height = null
  207. }
  208. setBase(base) {
  209. this.base = base
  210. }
  211. setWidth(width) {
  212. this.width = width
  213. }
  214. getBase() {
  215. return this.base
  216. }
  217. getWidth() {
  218. return this.width
  219. }
  220. setEnvelope(env) {
  221. this.width = env.getWidth()
  222. this.height = env.getHeight()
  223. this.base = new Coordinate(env.getMinX(), env.getMinY())
  224. this.centre = new Coordinate(env.centre())
  225. }
  226. setCentre(centre) {
  227. this.centre = centre
  228. }
  229. getMinSize() {
  230. return Math.min(this.width, this.height)
  231. }
  232. getEnvelope() {
  233. if (this.base !== null)
  234. return new Envelope(this.base.x, this.base.x + this.width, this.base.y, this.base.y + this.height)
  235. if (this.centre !== null)
  236. return new Envelope(this.centre.x - this.width / 2, this.centre.x + this.width / 2, this.centre.y - this.height / 2, this.centre.y + this.height / 2)
  237. return new Envelope(0, this.width, 0, this.height)
  238. }
  239. getCentre() {
  240. if (this.centre === null)
  241. this.centre = new Coordinate(this.base.x + this.width / 2, this.base.y + this.height / 2)
  242. return this.centre
  243. }
  244. getHeight() {
  245. return this.height
  246. }
  247. setHeight(height) {
  248. this.height = height
  249. }
  250. setSize(size) {
  251. this.height = size
  252. this.width = size
  253. }
  254. }
  255. GeometricShapeFactory.Dimensions = Dimensions