-
Notifications
You must be signed in to change notification settings - Fork 2
/
epoly.js
executable file
·223 lines (206 loc) · 9.94 KB
/
epoly.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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/*********************************************************************\
* *
* epolys.js by Mike Williams *
* *
* A Google Maps API Extension *
* *
* Adds various Methods to GPolygon and GPolyline *
* *
* .Contains(latlng) returns true is the poly contains the specified *
* GLatLng *
* *
* .Area() returns the approximate area of a poly that is *
* not self-intersecting *
* *
* .Distance() returns the length of the poly path *
* *
* .Bounds() returns a GLatLngBounds that bounds the poly *
* *
* .GetPointAtDistance() returns a GLatLng at the specified distance *
* along the path. *
* The distance is specified in metres *
* Reurns null if the path is shorter than that *
* *
* .GetPointsAtDistance() returns an array of GLatLngs at the *
* specified interval along the path. *
* The distance is specified in metres *
* *
* .GetIndexAtDistance() returns the vertex number at the specified *
* distance along the path. *
* The distance is specified in metres *
* Reurns null if the path is shorter than that *
* *
* .Bearing(v1?,v2?) returns the bearing between two vertices *
* if v1 is null, returns bearing from first to last *
* if v2 is null, returns bearing from v1 to next *
* *
* *
***********************************************************************
* *
* This Javascript is provided by Mike Williams *
* Community Church Javascript Team *
* http://www.bisphamchurch.org.uk/ *
* http://econym.org.uk/gmap/ *
* *
* This work is licenced under a Creative Commons Licence *
* http://creativecommons.org/licenses/by/2.0/uk/ *
* *
***********************************************************************
* *
* Version 1.1 6-Jun-2007 *
* Version 1.2 1-Jul-2007 - fix: Bounds was omitting vertex zero *
* add: Bearing *
* Version 1.3 28-Nov-2008 add: GetPointsAtDistance() *
* Version 1.4 12-Jan-2009 fix: GetPointsAtDistance() *
* *
\*********************************************************************/
// === A method for testing if a point is inside a polygon
// === Returns true if poly contains point
// === Algorithm shamelessly stolen from http://alienryderflex.com/polygon/
GPolygon.prototype.Contains = function(point) {
var j=0;
var oddNodes = false;
var x = point.lng();
var y = point.lat();
for (var i=0; i < this.getVertexCount(); i++) {
j++;
if (j == this.getVertexCount()) {j = 0;}
if (((this.getVertex(i).lat() < y) && (this.getVertex(j).lat() >= y))
|| ((this.getVertex(j).lat() < y) && (this.getVertex(i).lat() >= y))) {
if ( this.getVertex(i).lng() + (y - this.getVertex(i).lat())
/ (this.getVertex(j).lat()-this.getVertex(i).lat())
* (this.getVertex(j).lng() - this.getVertex(i).lng())<x ) {
oddNodes = !oddNodes
}
}
}
return oddNodes;
}
// === A method which returns the approximate area of a non-intersecting polygon in square metres ===
// === It doesn't fully account for spechical geometry, so will be inaccurate for large polygons ===
// === The polygon must not intersect itself ===
GPolygon.prototype.Area = function() {
var a = 0;
var j = 0;
var b = this.Bounds();
var x0 = b.getSouthWest().lng();
var y0 = b.getSouthWest().lat();
for (var i=0; i < this.getVertexCount(); i++) {
j++;
if (j == this.getVertexCount()) {j = 0;}
var x1 = this.getVertex(i).distanceFrom(new GLatLng(this.getVertex(i).lat(),x0));
var x2 = this.getVertex(j).distanceFrom(new GLatLng(this.getVertex(j).lat(),x0));
var y1 = this.getVertex(i).distanceFrom(new GLatLng(y0,this.getVertex(i).lng()));
var y2 = this.getVertex(j).distanceFrom(new GLatLng(y0,this.getVertex(j).lng()));
a += x1*y2 - x2*y1;
}
return Math.abs(a * 0.5);
}
// === A method which returns the length of a path in metres ===
GPolygon.prototype.Distance = function() {
var dist = 0;
for (var i=1; i < this.getVertexCount(); i++) {
dist += this.getVertex(i).distanceFrom(this.getVertex(i-1));
}
return dist;
}
// === A method which returns the bounds as a GLatLngBounds ===
GPolygon.prototype.Bounds = function() {
var bounds = new GLatLngBounds();
for (var i=0; i < this.getVertexCount(); i++) {
bounds.extend(this.getVertex(i));
}
return bounds;
}
// === A method which returns a GLatLng of a point a given distance along the path ===
// === Returns null if the path is shorter than the specified distance ===
GPolygon.prototype.GetPointAtDistance = function(metres) {
// some awkward special cases
if (metres == 0) return this.getVertex(0);
if (metres < 0) return null;
var dist=0;
var olddist=0;
for (var i=1; (i < this.getVertexCount() && dist < metres); i++) {
olddist = dist;
dist += this.getVertex(i).distanceFrom(this.getVertex(i-1));
}
if (dist < metres) {return null;}
var p1= this.getVertex(i-2);
var p2= this.getVertex(i-1);
var m = (metres-olddist)/(dist-olddist);
return new GLatLng( p1.lat() + (p2.lat()-p1.lat())*m, p1.lng() + (p2.lng()-p1.lng())*m);
}
// === A method which returns an array of GLatLngs of points a given interval along the path ===
GPolygon.prototype.GetPointsAtDistance = function(metres) {
var next = metres;
var points = [];
// some awkward special cases
if (metres <= 0) return points;
var dist=0;
var olddist=0;
for (var i=1; (i < this.getVertexCount()); i++) {
olddist = dist;
dist += this.getVertex(i).distanceFrom(this.getVertex(i-1));
while (dist > next) {
var p1= this.getVertex(i-1);
var p2= this.getVertex(i);
var m = (next-olddist)/(dist-olddist);
points.push(new GLatLng( p1.lat() + (p2.lat()-p1.lat())*m, p1.lng() + (p2.lng()-p1.lng())*m));
next += metres;
}
}
return points;
}
// === A method which returns the Vertex number at a given distance along the path ===
// === Returns null if the path is shorter than the specified distance ===
GPolygon.prototype.GetIndexAtDistance = function(metres) {
// some awkward special cases
if (metres == 0) return this.getVertex(0);
if (metres < 0) return null;
var dist=0;
var olddist=0;
for (var i=1; (i < this.getVertexCount() && dist < metres); i++) {
olddist = dist;
dist += this.getVertex(i).distanceFrom(this.getVertex(i-1));
}
if (dist < metres) {return null;}
return i;
}
// === A function which returns the bearing between two vertices in decgrees from 0 to 360===
// === If v1 is null, it returns the bearing between the first and last vertex ===
// === If v1 is present but v2 is null, returns the bearing from v1 to the next vertex ===
// === If either vertex is out of range, returns void ===
GPolygon.prototype.Bearing = function(v1,v2) {
if (v1 == null) {
v1 = 0;
v2 = this.getVertexCount()-1;
} else if (v2 == null) {
v2 = v1+1;
}
if ((v1 < 0) || (v1 >= this.getVertexCount()) || (v2 < 0) || (v2 >= this.getVertexCount())) {
return;
}
var from = this.getVertex(v1);
var to = this.getVertex(v2);
if (from.equals(to)) {
return 0;
}
var lat1 = from.latRadians();
var lon1 = from.lngRadians();
var lat2 = to.latRadians();
var lon2 = to.lngRadians();
var angle = - Math.atan2( Math.sin( lon1 - lon2 ) * Math.cos( lat2 ), Math.cos( lat1 ) * Math.sin( lat2 ) - Math.sin( lat1 ) * Math.cos( lat2 ) * Math.cos( lon1 - lon2 ) );
if ( angle < 0.0 ) angle += Math.PI * 2.0;
angle = angle * 180.0 / Math.PI;
return parseFloat(angle.toFixed(1));
}
GPolyline.prototype.strClassName = "GPolyline";
// === Copy all the above functions to GPolyline ===
GPolyline.prototype.Contains = GPolygon.prototype.Contains;
GPolyline.prototype.Area = GPolygon.prototype.Area;
GPolyline.prototype.Distance = GPolygon.prototype.Distance;
GPolyline.prototype.Bounds = GPolygon.prototype.Bounds;
GPolyline.prototype.GetPointAtDistance = GPolygon.prototype.GetPointAtDistance;
GPolyline.prototype.GetPointsAtDistance = GPolygon.prototype.GetPointsAtDistance;
GPolyline.prototype.GetIndexAtDistance = GPolygon.prototype.GetIndexAtDistance;
GPolyline.prototype.Bearing = GPolygon.prototype.Bearing;