-
Notifications
You must be signed in to change notification settings - Fork 3
/
epoly.js
157 lines (146 loc) · 5.77 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
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));
}
// === 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;