forked from hayeswise/Leaflet.PointInPolygon
-
Notifications
You must be signed in to change notification settings - Fork 0
/
wise-leaflet-pip.js
163 lines (157 loc) · 6.92 KB
/
wise-leaflet-pip.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/******************************************************************************
* Leaflet.PointInPolygon
* @author Brian S Hayes (Hayeswise)
* @license MIT License, Copyright (c) 2017 Brian Hayes ("Hayeswise")
*
* Thanks to:<br>
* Dan Sunday's Winding Number and isLeft C++ implementation - http://geomalgorithms.com/.
* Copyright and License: http://geomalgorithms.com/a03-_inclusion.html
* Leaflet.Geodesic by Kevin Brasier (a.k.a. Fragger)<br>
*/
/**
* Leaflet
* @external L
* @see {@link http://leafletjs.com/|Leaflet}
*/
/**
* Latitutde and longitude class.
* @name LatLng
* @member external:L.LatLng
* @see {@link http://leafletjs.com/ Leaflet} documentation for further information.
*/
/**
* The Leaflet Polyline class.
* @name Polyline
* @member external:L.Polyline
* @see {@link http://leafletjs.com/ Leaflet} documentation for further information.
*/
/**
* The Leaflet Polygon class.
* L.GeodesicPolygon and L.GeodesicCircle extend L.Polygon.
* @name Polygon
* @member external:L.Polygon
* @see {@link http://leafletjs.com/ Leaflet} documentation for further information.
*/
/**
* Hayeswise Point-in-polygon for Leaflet: A plugin for Leaflet that provides
* points-in-polygons functions based on Dan Sunday's C++ winding number implementation.
* @module {function} wiseLeafletPip
* @param {function} Leaflet namespace object.
* @see {@link https://github.com/hayeswise/Leaflet.PointInPolygon|Leaflet.PointInPolygon}
* @see {@link http://geomalgorithms.com/a03-_inclusion.html Inclusion of a Point in a Polygon} by Dan Sunday.
*/
(function(L) {
"use strict";
/**
* Checks if a single point is contained in a polyline or polygon (L.Polygon extends L.Polyline).
* <p>
* Note that L.Polygon, L.GeodesicPolygons, and L.GeodesicCircles are types of L.Polygon.
* @member external:L.Polyline.contains
* @param {L.LatLng} p A geographical point with a latitude and longitude.
* @returns {boolean} True if the point is contained in the polygon or polyline; otherwise,
* @see {@link https://github.com/Fragger/Leaflet.Geodesic Leaflet.Geodesc} for information about Leaflet.Geodesc by Fragger.
*/
L.Polyline.prototype.contains = function (p) {
//"use strict";
var rectangularBounds = this.getBounds(); // It appears that this is O(1): the LatLngBounds is updated as points are added to the polygon when it is created.
var wn;
if (rectangularBounds.contains(p)) {
wn = this.getWindingNumber(p);
return (wn !== 0);
} else {
return false;
}
};
/**
* Tests if a point is left|on|right of an infinite line.
* <br><br>
* This is a JavaScript and Leaflet port of the `isLeft()` C++ function by Dan Sunday.
* @member external:L.LatLng.isLeft
* @param {LatLng} p1 Point The reference line is defined by `this` LatLng to p1.
* @param {LatLng} p2 The point in question.
* @returns {Number} >0 for p2 left of the line through this point and p1,
* =0 for p2 on the line,
* <0 for p2 right of the line through this point an p1.
* @see {@link http://geomalgorithms.com/a03-_inclusion.html Inclusion of a Point in a Polygon} by Dan Sunday.
*/
L.LatLng.prototype.isLeft = function (p1, p2) {
return ((p1.lng - this.lng) * (p2.lat - this.lat) -
(p2.lng - this.lng) * (p1.lat - this.lat));
};
/**
* Test for a point in a polygon or on the bounding lines of the polygon. The
* coordinates (L.LatLngs) for a GeodesicPolygon are set to follow the earth's
* curvature when the GeodesicPolygon object is created. Since L.Polygon
* extends L.Polyline we can use the same method for both. Although, for
* L.Polyline, we only get points on the line even if a collection of lines
* appear to make a polygon.
* <br><br>
* This is a JavaScript and Leaflet port of the `wn_PnPoly()` C++ function by Dan Sunday.
* Unlike the C++ version, this implementation does include points on the line and vertices.
*
* @member external:L.Polyline.getWindingNumber
* @param p {L.LatLng} A point.
* @returns {Number} The winding number (=0 only when the point is outside)
*
* @see {@link http://geomalgorithms.com/a03-_inclusion.html Inclusion of a Point in a Polygon} by Dan Sunday.
* @see {@link https://github.com/Fragger/Leaflet.Geodesic Leaflet.Geodesc} for information about Leaflet.Geodesc by Fragger.
*/
L.Polyline.prototype.getWindingNumber = function (p) { // Note that L.Polygon extends L.Polyline
var i,
isLeftTest,
n,
vertices,
wn; // the winding number counter
function flatten(a) {
var flat;
flat = ((Array.isArray ? Array.isArray(a) : L.Util.isArray(a)) ? a.reduce(function (accumulator, v, i, array) {
return accumulator.concat(Array.isArray(v) ? flatten(v) : v);
}, [])
: a);
return flat;
}
vertices = this.getLatLngs();
vertices = flatten(vertices); // Flatten array of LatLngs since multi-polylines return nested array.
// Filter out duplicate vertices.
vertices = vertices.filter(function (v, i, array) { // remove adjacent duplicates
if (i > 0 && v.lat === array[i-1].lat && v.lng === array[i-1].lng) {
return false;
} else {
return true;
}
});
n = vertices.length;
// Note that per the algorithm, the vertices (V) must be "a vertex points of a polygon V[n+1] with V[n]=V[0]"
if (n > 0 && !(vertices[n-1].lat === vertices[0].lat && vertices[n-1].lng === vertices[0].lng)) {
vertices.push(vertices[0]);
}
n = vertices.length - 1;
wn = 0;
for (i=0; i < n; i++) {
isLeftTest = vertices[i].isLeft(vertices[i+1], p);
if (isLeftTest === 0) { // If the point is on a line, we are done.
wn = 1;
break;
} else {
if (isLeftTest !== 0) { // If not a vertex or on line (the C++ version does not check for this)
if (vertices[i].lat <= p.lat) {
if (vertices[i+1].lat > p.lat) { // An upward crossing
if (isLeftTest > 0) { // P left of edge
wn++; // have a valid up intersect
}
}
} else {
if (vertices[i+1].lat <= p.lat) {// A downward crossing
if (isLeftTest < 0) { // P right of edge
wn--; // have a valid down intersect
}
}
}
} else {
wn++;
}
}
}
return wn;
};
})(L); //L is set to Leaflet's L