Centroid.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import LineString from '../geom/LineString'
  2. import Geometry from '../geom/Geometry'
  3. import Coordinate from '../geom/Coordinate'
  4. import Point from '../geom/Point'
  5. import Polygon from '../geom/Polygon'
  6. import Orientation from './Orientation'
  7. import GeometryCollection from '../geom/GeometryCollection'
  8. export default class Centroid {
  9. constructor() {
  10. Centroid.constructor_.apply(this, arguments)
  11. }
  12. static constructor_() {
  13. this._areaBasePt = null
  14. this._triangleCent3 = new Coordinate()
  15. this._areasum2 = 0
  16. this._cg3 = new Coordinate()
  17. this._lineCentSum = new Coordinate()
  18. this._totalLength = 0.0
  19. this._ptCount = 0
  20. this._ptCentSum = new Coordinate()
  21. const geom = arguments[0]
  22. this._areaBasePt = null
  23. this.add(geom)
  24. }
  25. static area2(p1, p2, p3) {
  26. return (p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y)
  27. }
  28. static centroid3(p1, p2, p3, c) {
  29. c.x = p1.x + p2.x + p3.x
  30. c.y = p1.y + p2.y + p3.y
  31. return null
  32. }
  33. static getCentroid(geom) {
  34. const cent = new Centroid(geom)
  35. return cent.getCentroid()
  36. }
  37. setAreaBasePoint(basePt) {
  38. this._areaBasePt = basePt
  39. }
  40. addPoint(pt) {
  41. this._ptCount += 1
  42. this._ptCentSum.x += pt.x
  43. this._ptCentSum.y += pt.y
  44. }
  45. addLineSegments(pts) {
  46. let lineLen = 0.0
  47. for (let i = 0; i < pts.length - 1; i++) {
  48. const segmentLen = pts[i].distance(pts[i + 1])
  49. if (segmentLen === 0.0) continue
  50. lineLen += segmentLen
  51. const midx = (pts[i].x + pts[i + 1].x) / 2
  52. this._lineCentSum.x += segmentLen * midx
  53. const midy = (pts[i].y + pts[i + 1].y) / 2
  54. this._lineCentSum.y += segmentLen * midy
  55. }
  56. this._totalLength += lineLen
  57. if (lineLen === 0.0 && pts.length > 0) this.addPoint(pts[0])
  58. }
  59. addHole(pts) {
  60. const isPositiveArea = Orientation.isCCW(pts)
  61. for (let i = 0; i < pts.length - 1; i++)
  62. this.addTriangle(this._areaBasePt, pts[i], pts[i + 1], isPositiveArea)
  63. this.addLineSegments(pts)
  64. }
  65. getCentroid() {
  66. const cent = new Coordinate()
  67. if (Math.abs(this._areasum2) > 0.0) {
  68. cent.x = this._cg3.x / 3 / this._areasum2
  69. cent.y = this._cg3.y / 3 / this._areasum2
  70. } else if (this._totalLength > 0.0) {
  71. cent.x = this._lineCentSum.x / this._totalLength
  72. cent.y = this._lineCentSum.y / this._totalLength
  73. } else if (this._ptCount > 0) {
  74. cent.x = this._ptCentSum.x / this._ptCount
  75. cent.y = this._ptCentSum.y / this._ptCount
  76. } else {
  77. return null
  78. }
  79. return cent
  80. }
  81. addShell(pts) {
  82. if (pts.length > 0) this.setAreaBasePoint(pts[0])
  83. const isPositiveArea = !Orientation.isCCW(pts)
  84. for (let i = 0; i < pts.length - 1; i++)
  85. this.addTriangle(this._areaBasePt, pts[i], pts[i + 1], isPositiveArea)
  86. this.addLineSegments(pts)
  87. }
  88. addTriangle(p0, p1, p2, isPositiveArea) {
  89. const sign = isPositiveArea ? 1.0 : -1.0
  90. Centroid.centroid3(p0, p1, p2, this._triangleCent3)
  91. const area2 = Centroid.area2(p0, p1, p2)
  92. this._cg3.x += sign * area2 * this._triangleCent3.x
  93. this._cg3.y += sign * area2 * this._triangleCent3.y
  94. this._areasum2 += sign * area2
  95. }
  96. add() {
  97. if (arguments[0] instanceof Polygon) {
  98. const poly = arguments[0]
  99. this.addShell(poly.getExteriorRing().getCoordinates())
  100. for (let i = 0; i < poly.getNumInteriorRing(); i++)
  101. this.addHole(poly.getInteriorRingN(i).getCoordinates())
  102. } else if (arguments[0] instanceof Geometry) {
  103. const geom = arguments[0]
  104. if (geom.isEmpty()) return null
  105. if (geom instanceof Point) {
  106. this.addPoint(geom.getCoordinate())
  107. } else if (geom instanceof LineString) {
  108. this.addLineSegments(geom.getCoordinates())
  109. } else if (geom instanceof Polygon) {
  110. const poly = geom
  111. this.add(poly)
  112. } else if (geom instanceof GeometryCollection) {
  113. const gc = geom
  114. for (let i = 0; i < gc.getNumGeometries(); i++)
  115. this.add(gc.getGeometryN(i))
  116. }
  117. }
  118. }
  119. }