RayCrossingCounter.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import Location from '../geom/Location'
  2. import hasInterface from '../../../../hasInterface'
  3. import Coordinate from '../geom/Coordinate'
  4. import Orientation from './Orientation'
  5. import CoordinateSequence from '../geom/CoordinateSequence'
  6. export default class RayCrossingCounter {
  7. constructor() {
  8. RayCrossingCounter.constructor_.apply(this, arguments)
  9. }
  10. static constructor_() {
  11. this._p = null
  12. this._crossingCount = 0
  13. this._isPointOnSegment = false
  14. const p = arguments[0]
  15. this._p = p
  16. }
  17. static locatePointInRing() {
  18. if (arguments[0] instanceof Coordinate && hasInterface(arguments[1], CoordinateSequence)) {
  19. const p = arguments[0], ring = arguments[1]
  20. const counter = new RayCrossingCounter(p)
  21. const p1 = new Coordinate()
  22. const p2 = new Coordinate()
  23. for (let i = 1; i < ring.size(); i++) {
  24. ring.getCoordinate(i, p1)
  25. ring.getCoordinate(i - 1, p2)
  26. counter.countSegment(p1, p2)
  27. if (counter.isOnSegment()) return counter.getLocation()
  28. }
  29. return counter.getLocation()
  30. } else if (arguments[0] instanceof Coordinate && arguments[1] instanceof Array) {
  31. const p = arguments[0], ring = arguments[1]
  32. const counter = new RayCrossingCounter(p)
  33. for (let i = 1; i < ring.length; i++) {
  34. const p1 = ring[i]
  35. const p2 = ring[i - 1]
  36. counter.countSegment(p1, p2)
  37. if (counter.isOnSegment()) return counter.getLocation()
  38. }
  39. return counter.getLocation()
  40. }
  41. }
  42. countSegment(p1, p2) {
  43. if (p1.x < this._p.x && p2.x < this._p.x) return null
  44. if (this._p.x === p2.x && this._p.y === p2.y) {
  45. this._isPointOnSegment = true
  46. return null
  47. }
  48. if (p1.y === this._p.y && p2.y === this._p.y) {
  49. let minx = p1.x
  50. let maxx = p2.x
  51. if (minx > maxx) {
  52. minx = p2.x
  53. maxx = p1.x
  54. }
  55. if (this._p.x >= minx && this._p.x <= maxx)
  56. this._isPointOnSegment = true
  57. return null
  58. }
  59. if (p1.y > this._p.y && p2.y <= this._p.y || p2.y > this._p.y && p1.y <= this._p.y) {
  60. let orient = Orientation.index(p1, p2, this._p)
  61. if (orient === Orientation.COLLINEAR) {
  62. this._isPointOnSegment = true
  63. return null
  64. }
  65. if (p2.y < p1.y)
  66. orient = -orient
  67. if (orient === Orientation.LEFT)
  68. this._crossingCount++
  69. }
  70. }
  71. isPointInPolygon() {
  72. return this.getLocation() !== Location.EXTERIOR
  73. }
  74. getLocation() {
  75. if (this._isPointOnSegment) return Location.BOUNDARY
  76. if (this._crossingCount % 2 === 1)
  77. return Location.INTERIOR
  78. return Location.EXTERIOR
  79. }
  80. isOnSegment() {
  81. return this._isPointOnSegment
  82. }
  83. }