1 | import {Point} from './Point';
|
2 | import * as Util from '../core/Util';
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 | export function simplify(points, tolerance) {
|
23 | if (!tolerance || !points.length) {
|
24 | return points.slice();
|
25 | }
|
26 |
|
27 | var sqTolerance = tolerance * tolerance;
|
28 |
|
29 |
|
30 | points = _reducePoints(points, sqTolerance);
|
31 |
|
32 |
|
33 | points = _simplifyDP(points, sqTolerance);
|
34 |
|
35 | return points;
|
36 | }
|
37 |
|
38 |
|
39 |
|
40 | export function pointToSegmentDistance(p, p1, p2) {
|
41 | return Math.sqrt(_sqClosestPointOnSegment(p, p1, p2, true));
|
42 | }
|
43 |
|
44 |
|
45 |
|
46 | export function closestPointOnSegment(p, p1, p2) {
|
47 | return _sqClosestPointOnSegment(p, p1, p2);
|
48 | }
|
49 |
|
50 |
|
51 | function _simplifyDP(points, sqTolerance) {
|
52 |
|
53 | var len = points.length,
|
54 | ArrayConstructor = typeof Uint8Array !== undefined + '' ? Uint8Array : Array,
|
55 | markers = new ArrayConstructor(len);
|
56 |
|
57 | markers[0] = markers[len - 1] = 1;
|
58 |
|
59 | _simplifyDPStep(points, markers, sqTolerance, 0, len - 1);
|
60 |
|
61 | var i,
|
62 | newPoints = [];
|
63 |
|
64 | for (i = 0; i < len; i++) {
|
65 | if (markers[i]) {
|
66 | newPoints.push(points[i]);
|
67 | }
|
68 | }
|
69 |
|
70 | return newPoints;
|
71 | }
|
72 |
|
73 | function _simplifyDPStep(points, markers, sqTolerance, first, last) {
|
74 |
|
75 | var maxSqDist = 0,
|
76 | index, i, sqDist;
|
77 |
|
78 | for (i = first + 1; i <= last - 1; i++) {
|
79 | sqDist = _sqClosestPointOnSegment(points[i], points[first], points[last], true);
|
80 |
|
81 | if (sqDist > maxSqDist) {
|
82 | index = i;
|
83 | maxSqDist = sqDist;
|
84 | }
|
85 | }
|
86 |
|
87 | if (maxSqDist > sqTolerance) {
|
88 | markers[index] = 1;
|
89 |
|
90 | _simplifyDPStep(points, markers, sqTolerance, first, index);
|
91 | _simplifyDPStep(points, markers, sqTolerance, index, last);
|
92 | }
|
93 | }
|
94 |
|
95 |
|
96 | function _reducePoints(points, sqTolerance) {
|
97 | var reducedPoints = [points[0]];
|
98 |
|
99 | for (var i = 1, prev = 0, len = points.length; i < len; i++) {
|
100 | if (_sqDist(points[i], points[prev]) > sqTolerance) {
|
101 | reducedPoints.push(points[i]);
|
102 | prev = i;
|
103 | }
|
104 | }
|
105 | if (prev < len - 1) {
|
106 | reducedPoints.push(points[len - 1]);
|
107 | }
|
108 | return reducedPoints;
|
109 | }
|
110 |
|
111 | var _lastCode;
|
112 |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 |
|
118 | export function clipSegment(a, b, bounds, useLastCode, round) {
|
119 | var codeA = useLastCode ? _lastCode : _getBitCode(a, bounds),
|
120 | codeB = _getBitCode(b, bounds),
|
121 |
|
122 | codeOut, p, newCode;
|
123 |
|
124 |
|
125 | _lastCode = codeB;
|
126 |
|
127 | while (true) {
|
128 |
|
129 | if (!(codeA | codeB)) {
|
130 | return [a, b];
|
131 | }
|
132 |
|
133 |
|
134 | if (codeA & codeB) {
|
135 | return false;
|
136 | }
|
137 |
|
138 |
|
139 | codeOut = codeA || codeB;
|
140 | p = _getEdgeIntersection(a, b, codeOut, bounds, round);
|
141 | newCode = _getBitCode(p, bounds);
|
142 |
|
143 | if (codeOut === codeA) {
|
144 | a = p;
|
145 | codeA = newCode;
|
146 | } else {
|
147 | b = p;
|
148 | codeB = newCode;
|
149 | }
|
150 | }
|
151 | }
|
152 |
|
153 | export function _getEdgeIntersection(a, b, code, bounds, round) {
|
154 | var dx = b.x - a.x,
|
155 | dy = b.y - a.y,
|
156 | min = bounds.min,
|
157 | max = bounds.max,
|
158 | x, y;
|
159 |
|
160 | if (code & 8) {
|
161 | x = a.x + dx * (max.y - a.y) / dy;
|
162 | y = max.y;
|
163 |
|
164 | } else if (code & 4) {
|
165 | x = a.x + dx * (min.y - a.y) / dy;
|
166 | y = min.y;
|
167 |
|
168 | } else if (code & 2) {
|
169 | x = max.x;
|
170 | y = a.y + dy * (max.x - a.x) / dx;
|
171 |
|
172 | } else if (code & 1) {
|
173 | x = min.x;
|
174 | y = a.y + dy * (min.x - a.x) / dx;
|
175 | }
|
176 |
|
177 | return new Point(x, y, round);
|
178 | }
|
179 |
|
180 | export function _getBitCode(p, bounds) {
|
181 | var code = 0;
|
182 |
|
183 | if (p.x < bounds.min.x) {
|
184 | code |= 1;
|
185 | } else if (p.x > bounds.max.x) {
|
186 | code |= 2;
|
187 | }
|
188 |
|
189 | if (p.y < bounds.min.y) {
|
190 | code |= 4;
|
191 | } else if (p.y > bounds.max.y) {
|
192 | code |= 8;
|
193 | }
|
194 |
|
195 | return code;
|
196 | }
|
197 |
|
198 |
|
199 | function _sqDist(p1, p2) {
|
200 | var dx = p2.x - p1.x,
|
201 | dy = p2.y - p1.y;
|
202 | return dx * dx + dy * dy;
|
203 | }
|
204 |
|
205 |
|
206 | export function _sqClosestPointOnSegment(p, p1, p2, sqDist) {
|
207 | var x = p1.x,
|
208 | y = p1.y,
|
209 | dx = p2.x - x,
|
210 | dy = p2.y - y,
|
211 | dot = dx * dx + dy * dy,
|
212 | t;
|
213 |
|
214 | if (dot > 0) {
|
215 | t = ((p.x - x) * dx + (p.y - y) * dy) / dot;
|
216 |
|
217 | if (t > 1) {
|
218 | x = p2.x;
|
219 | y = p2.y;
|
220 | } else if (t > 0) {
|
221 | x += dx * t;
|
222 | y += dy * t;
|
223 | }
|
224 | }
|
225 |
|
226 | dx = p.x - x;
|
227 | dy = p.y - y;
|
228 |
|
229 | return sqDist ? dx * dx + dy * dy : new Point(x, y);
|
230 | }
|
231 |
|
232 |
|
233 |
|
234 |
|
235 | export function isFlat(latlngs) {
|
236 | return !Util.isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined');
|
237 | }
|
238 |
|
239 | export function _flat(latlngs) {
|
240 | console.warn('Deprecated use of _flat, please use L.LineUtil.isFlat instead.');
|
241 | return isFlat(latlngs);
|
242 | }
|