1 | import Point from '@mapbox/point-geometry';
|
2 | import Transform from './transform';
|
3 | import LngLat from './lng_lat';
|
4 | import {OverscaledTileID, CanonicalTileID} from '../source/tile_id';
|
5 | import {fixedLngLat, fixedCoord} from '../../test/unit/lib/fixed';
|
6 |
|
7 | describe('transform', () => {
|
8 | test('creates a transform', () => {
|
9 | const transform = new Transform(0, 22, 0, 60, true);
|
10 | transform.resize(500, 500);
|
11 | expect(transform.unmodified).toBe(true);
|
12 | expect(transform.maxValidLatitude).toBe(85.051129);
|
13 | expect(transform.tileSize).toBe(512);
|
14 | expect(transform.worldSize).toBe(512);
|
15 | expect(transform.width).toBe(500);
|
16 | expect(transform.minZoom).toBe(0);
|
17 | expect(transform.minPitch).toBe(0);
|
18 |
|
19 | expect(transform.bearing === 0 ? 0 : transform.bearing).toBe(0);
|
20 | expect(transform.bearing = 1).toBe(1);
|
21 | expect(transform.bearing).toBe(1);
|
22 | expect(transform.bearing = 0).toBe(0);
|
23 | expect(transform.unmodified).toBe(false);
|
24 | expect(transform.minZoom = 10).toBe(10);
|
25 | expect(transform.maxZoom = 10).toBe(10);
|
26 | expect(transform.minZoom).toBe(10);
|
27 | expect(transform.center).toEqual({lng: 0, lat: 0});
|
28 | expect(transform.maxZoom).toBe(10);
|
29 | expect(transform.minPitch = 10).toBe(10);
|
30 | expect(transform.maxPitch = 10).toBe(10);
|
31 | expect(transform.size.equals(new Point(500, 500))).toBe(true);
|
32 | expect(transform.centerPoint.equals(new Point(250, 250))).toBe(true);
|
33 | expect(transform.scaleZoom(0)).toBe(-Infinity);
|
34 | expect(transform.scaleZoom(10)).toBe(3.3219280948873626);
|
35 | expect(transform.point).toEqual(new Point(262144, 262144));
|
36 | expect(transform.height).toBe(500);
|
37 | expect(fixedLngLat(transform.pointLocation(new Point(250, 250)))).toEqual({lng: 0, lat: 0});
|
38 | expect(fixedCoord(transform.pointCoordinate(new Point(250, 250)))).toEqual({x: 0.5, y: 0.5, z: 0});
|
39 | expect(transform.locationPoint(new LngLat(0, 0))).toEqual({x: 250, y: 250});
|
40 | expect(transform.locationCoordinate(new LngLat(0, 0))).toEqual({x: 0.5, y: 0.5, z: 0});
|
41 | });
|
42 |
|
43 | test('does not throw on bad center', () => {
|
44 | expect(() => {
|
45 | const transform = new Transform(0, 22, 0, 60, true);
|
46 | transform.resize(500, 500);
|
47 | transform.center = new LngLat(50, -90);
|
48 | }).not.toThrow();
|
49 | });
|
50 |
|
51 | test('setLocationAt', () => {
|
52 | const transform = new Transform(0, 22, 0, 60, true);
|
53 | transform.resize(500, 500);
|
54 | transform.zoom = 4;
|
55 | expect(transform.center).toEqual({lng: 0, lat: 0});
|
56 | transform.setLocationAtPoint(new LngLat(13, 10), new Point(15, 45));
|
57 | expect(fixedLngLat(transform.pointLocation(new Point(15, 45)))).toEqual({lng: 13, lat: 10});
|
58 | });
|
59 |
|
60 | test('setLocationAt tilted', () => {
|
61 | const transform = new Transform(0, 22, 0, 60, true);
|
62 | transform.resize(500, 500);
|
63 | transform.zoom = 4;
|
64 | transform.pitch = 50;
|
65 | expect(transform.center).toEqual({lng: 0, lat: 0});
|
66 | transform.setLocationAtPoint(new LngLat(13, 10), new Point(15, 45));
|
67 | expect(fixedLngLat(transform.pointLocation(new Point(15, 45)))).toEqual({lng: 13, lat: 10});
|
68 | });
|
69 |
|
70 | test('has a default zoom', () => {
|
71 | const transform = new Transform(0, 22, 0, 60, true);
|
72 | transform.resize(500, 500);
|
73 | expect(transform.tileZoom).toBe(0);
|
74 | expect(transform.tileZoom).toBe(transform.zoom);
|
75 | });
|
76 |
|
77 | test('set fov', () => {
|
78 | const transform = new Transform(0, 22, 0, 60, true);
|
79 | transform.fov = 10;
|
80 | expect(transform.fov).toBe(10);
|
81 | transform.fov = 10;
|
82 | expect(transform.fov).toBe(10);
|
83 | });
|
84 |
|
85 | test('lngRange & latRange constrain zoom and center', () => {
|
86 | const transform = new Transform(0, 22, 0, 60, true);
|
87 | transform.center = new LngLat(0, 0);
|
88 | transform.zoom = 10;
|
89 | transform.resize(500, 500);
|
90 |
|
91 | transform.lngRange = [-5, 5];
|
92 | transform.latRange = [-5, 5];
|
93 |
|
94 | transform.zoom = 0;
|
95 | expect(transform.zoom).toBe(5.135709286104402);
|
96 |
|
97 | transform.center = new LngLat(-50, -30);
|
98 | expect(transform.center).toEqual(new LngLat(0, -0.0063583052861417855));
|
99 |
|
100 | transform.zoom = 10;
|
101 | transform.center = new LngLat(-50, -30);
|
102 | expect(transform.center).toEqual(new LngLat(-4.828338623046875, -4.828969771321582));
|
103 | });
|
104 |
|
105 | describe('coveringTiles', () => {
|
106 | const options = {
|
107 | minzoom: 1,
|
108 | maxzoom: 10,
|
109 | tileSize: 512
|
110 | };
|
111 |
|
112 | const transform = new Transform(0, 22, 0, 60, true);
|
113 | transform.resize(200, 200);
|
114 |
|
115 | test('generell', () => {
|
116 |
|
117 |
|
118 | transform.center = new LngLat(-0.01, 0.01);
|
119 |
|
120 | transform.zoom = 0;
|
121 | expect(transform.coveringTiles(options)).toEqual([]);
|
122 |
|
123 | transform.zoom = 1;
|
124 | expect(transform.coveringTiles(options)).toEqual([
|
125 | new OverscaledTileID(1, 0, 1, 0, 0),
|
126 | new OverscaledTileID(1, 0, 1, 1, 0),
|
127 | new OverscaledTileID(1, 0, 1, 0, 1),
|
128 | new OverscaledTileID(1, 0, 1, 1, 1)]);
|
129 |
|
130 | transform.zoom = 2.4;
|
131 | expect(transform.coveringTiles(options)).toEqual([
|
132 | new OverscaledTileID(2, 0, 2, 1, 1),
|
133 | new OverscaledTileID(2, 0, 2, 2, 1),
|
134 | new OverscaledTileID(2, 0, 2, 1, 2),
|
135 | new OverscaledTileID(2, 0, 2, 2, 2)]);
|
136 |
|
137 | transform.zoom = 10;
|
138 | expect(transform.coveringTiles(options)).toEqual([
|
139 | new OverscaledTileID(10, 0, 10, 511, 511),
|
140 | new OverscaledTileID(10, 0, 10, 512, 511),
|
141 | new OverscaledTileID(10, 0, 10, 511, 512),
|
142 | new OverscaledTileID(10, 0, 10, 512, 512)]);
|
143 |
|
144 | transform.zoom = 11;
|
145 | expect(transform.coveringTiles(options)).toEqual([
|
146 | new OverscaledTileID(10, 0, 10, 511, 511),
|
147 | new OverscaledTileID(10, 0, 10, 512, 511),
|
148 | new OverscaledTileID(10, 0, 10, 511, 512),
|
149 | new OverscaledTileID(10, 0, 10, 512, 512)]);
|
150 |
|
151 | transform.zoom = 5.1;
|
152 | transform.pitch = 60.0;
|
153 | transform.bearing = 32.0;
|
154 | transform.center = new LngLat(56.90, 48.20);
|
155 | transform.resize(1024, 768);
|
156 | expect(transform.coveringTiles(options)).toEqual([
|
157 | new OverscaledTileID(5, 0, 5, 21, 11),
|
158 | new OverscaledTileID(5, 0, 5, 20, 11),
|
159 | new OverscaledTileID(5, 0, 5, 21, 10),
|
160 | new OverscaledTileID(5, 0, 5, 20, 10),
|
161 | new OverscaledTileID(5, 0, 5, 21, 12),
|
162 | new OverscaledTileID(5, 0, 5, 22, 11),
|
163 | new OverscaledTileID(5, 0, 5, 20, 12),
|
164 | new OverscaledTileID(5, 0, 5, 22, 10),
|
165 | new OverscaledTileID(5, 0, 5, 21, 9),
|
166 | new OverscaledTileID(5, 0, 5, 20, 9),
|
167 | new OverscaledTileID(5, 0, 5, 22, 9),
|
168 | new OverscaledTileID(5, 0, 5, 23, 10),
|
169 | new OverscaledTileID(5, 0, 5, 21, 8),
|
170 | new OverscaledTileID(5, 0, 5, 20, 8),
|
171 | new OverscaledTileID(5, 0, 5, 23, 9),
|
172 | new OverscaledTileID(5, 0, 5, 22, 8),
|
173 | new OverscaledTileID(5, 0, 5, 23, 8),
|
174 | new OverscaledTileID(5, 0, 5, 21, 7),
|
175 | new OverscaledTileID(5, 0, 5, 20, 7),
|
176 | new OverscaledTileID(5, 0, 5, 24, 9),
|
177 | new OverscaledTileID(5, 0, 5, 22, 7)
|
178 | ]);
|
179 |
|
180 | transform.zoom = 8;
|
181 | transform.pitch = 60;
|
182 | transform.bearing = 45.0;
|
183 | transform.center = new LngLat(25.02, 60.15);
|
184 | transform.resize(300, 50);
|
185 | expect(transform.coveringTiles(options)).toEqual([
|
186 | new OverscaledTileID(8, 0, 8, 145, 74),
|
187 | new OverscaledTileID(8, 0, 8, 145, 73),
|
188 | new OverscaledTileID(8, 0, 8, 146, 74)
|
189 | ]);
|
190 |
|
191 | transform.resize(50, 300);
|
192 | expect(transform.coveringTiles(options)).toEqual([
|
193 | new OverscaledTileID(8, 0, 8, 145, 74),
|
194 | new OverscaledTileID(8, 0, 8, 145, 73),
|
195 | new OverscaledTileID(8, 0, 8, 146, 74),
|
196 | new OverscaledTileID(8, 0, 8, 146, 73)
|
197 | ]);
|
198 |
|
199 | transform.zoom = 2;
|
200 | transform.pitch = 0;
|
201 | transform.bearing = 0;
|
202 | transform.resize(300, 300);
|
203 | });
|
204 |
|
205 | test('calculates tile coverage at w > 0', () => {
|
206 | transform.center = new LngLat(630.01, 0.01);
|
207 | expect(transform.coveringTiles(options)).toEqual([
|
208 | new OverscaledTileID(2, 2, 2, 1, 1),
|
209 | new OverscaledTileID(2, 2, 2, 1, 2),
|
210 | new OverscaledTileID(2, 2, 2, 0, 1),
|
211 | new OverscaledTileID(2, 2, 2, 0, 2)
|
212 | ]);
|
213 | });
|
214 |
|
215 | test('calculates tile coverage at w = -1', () => {
|
216 | transform.center = new LngLat(-360.01, 0.01);
|
217 | expect(transform.coveringTiles(options)).toEqual([
|
218 | new OverscaledTileID(2, -1, 2, 1, 1),
|
219 | new OverscaledTileID(2, -1, 2, 1, 2),
|
220 | new OverscaledTileID(2, -1, 2, 2, 1),
|
221 | new OverscaledTileID(2, -1, 2, 2, 2)
|
222 | ]);
|
223 | });
|
224 |
|
225 | test('calculates tile coverage across meridian', () => {
|
226 | transform.zoom = 1;
|
227 | transform.center = new LngLat(-180.01, 0.01);
|
228 | expect(transform.coveringTiles(options)).toEqual([
|
229 | new OverscaledTileID(1, 0, 1, 0, 0),
|
230 | new OverscaledTileID(1, 0, 1, 0, 1),
|
231 | new OverscaledTileID(1, -1, 1, 1, 0),
|
232 | new OverscaledTileID(1, -1, 1, 1, 1)
|
233 | ]);
|
234 | });
|
235 |
|
236 | test('only includes tiles for a single world, if renderWorldCopies is set to false', () => {
|
237 | transform.zoom = 1;
|
238 | transform.center = new LngLat(-180.01, 0.01);
|
239 | transform.renderWorldCopies = false;
|
240 | expect(transform.coveringTiles(options)).toEqual([
|
241 | new OverscaledTileID(1, 0, 1, 0, 0),
|
242 | new OverscaledTileID(1, 0, 1, 0, 1)
|
243 | ]);
|
244 | });
|
245 |
|
246 | });
|
247 |
|
248 | test('coveringZoomLevel', () => {
|
249 | const options = {
|
250 | minzoom: 1,
|
251 | maxzoom: 10,
|
252 | tileSize: 512,
|
253 | roundZoom: false,
|
254 | };
|
255 |
|
256 | const transform = new Transform(0, 22, 0, 60, true);
|
257 |
|
258 | transform.zoom = 0;
|
259 | expect(transform.coveringZoomLevel(options)).toBe(0);
|
260 |
|
261 | transform.zoom = 0.1;
|
262 | expect(transform.coveringZoomLevel(options)).toBe(0);
|
263 |
|
264 | transform.zoom = 1;
|
265 | expect(transform.coveringZoomLevel(options)).toBe(1);
|
266 |
|
267 | transform.zoom = 2.4;
|
268 | expect(transform.coveringZoomLevel(options)).toBe(2);
|
269 |
|
270 | transform.zoom = 10;
|
271 | expect(transform.coveringZoomLevel(options)).toBe(10);
|
272 |
|
273 | transform.zoom = 11;
|
274 | expect(transform.coveringZoomLevel(options)).toBe(11);
|
275 |
|
276 | transform.zoom = 11.5;
|
277 | expect(transform.coveringZoomLevel(options)).toBe(11);
|
278 |
|
279 | options.tileSize = 256;
|
280 |
|
281 | transform.zoom = 0;
|
282 | expect(transform.coveringZoomLevel(options)).toBe(1);
|
283 |
|
284 | transform.zoom = 0.1;
|
285 | expect(transform.coveringZoomLevel(options)).toBe(1);
|
286 |
|
287 | transform.zoom = 1;
|
288 | expect(transform.coveringZoomLevel(options)).toBe(2);
|
289 |
|
290 | transform.zoom = 2.4;
|
291 | expect(transform.coveringZoomLevel(options)).toBe(3);
|
292 |
|
293 | transform.zoom = 10;
|
294 | expect(transform.coveringZoomLevel(options)).toBe(11);
|
295 |
|
296 | transform.zoom = 11;
|
297 | expect(transform.coveringZoomLevel(options)).toBe(12);
|
298 |
|
299 | transform.zoom = 11.5;
|
300 | expect(transform.coveringZoomLevel(options)).toBe(12);
|
301 |
|
302 | options.roundZoom = true;
|
303 |
|
304 | expect(transform.coveringZoomLevel(options)).toBe(13);
|
305 | });
|
306 |
|
307 | test('clamps latitude', () => {
|
308 | const transform = new Transform(0, 22, 0, 60, true);
|
309 |
|
310 | expect(transform.project(new LngLat(0, -90))).toEqual(transform.project(new LngLat(0, -transform.maxValidLatitude)));
|
311 | expect(transform.project(new LngLat(0, 90))).toEqual(transform.project(new LngLat(0, transform.maxValidLatitude)));
|
312 | });
|
313 |
|
314 | test('clamps pitch', () => {
|
315 | const transform = new Transform(0, 22, 0, 60, true);
|
316 |
|
317 | transform.pitch = 45;
|
318 | expect(transform.pitch).toBe(45);
|
319 |
|
320 | transform.pitch = -10;
|
321 | expect(transform.pitch).toBe(0);
|
322 |
|
323 | transform.pitch = 90;
|
324 | expect(transform.pitch).toBe(60);
|
325 | });
|
326 |
|
327 | test('visibleUnwrappedCoordinates', () => {
|
328 | const transform = new Transform(0, 22, 0, 60, true);
|
329 | transform.resize(200, 200);
|
330 | transform.zoom = 0;
|
331 | transform.center = new LngLat(-170.01, 0.01);
|
332 |
|
333 | let unwrappedCoords = transform.getVisibleUnwrappedCoordinates(new CanonicalTileID(0, 0, 0));
|
334 | expect(unwrappedCoords).toHaveLength(4);
|
335 |
|
336 |
|
337 | transform._renderWorldCopies = false;
|
338 | unwrappedCoords = transform.getVisibleUnwrappedCoordinates(new CanonicalTileID(0, 0, 0));
|
339 | expect(unwrappedCoords).toHaveLength(1);
|
340 | });
|
341 |
|
342 | test('maintains high float precision when calculating matrices', () => {
|
343 |
|
344 | const transform = new Transform(0, 22, 0, 60, true);
|
345 | transform.resize(200.25, 200.25);
|
346 | transform.zoom = 20.25;
|
347 | transform.pitch = 67.25;
|
348 | transform.center = new LngLat(0.0, 0.0);
|
349 | transform._calcMatrices();
|
350 |
|
351 | expect(transform.customLayerMatrix()[0].toString().length).toBeGreaterThan(10);
|
352 | expect(transform.glCoordMatrix[0].toString().length).toBeGreaterThan(10);
|
353 | expect(transform.maxPitchScaleFactor()).toBeCloseTo(2.366025418080343, 10);
|
354 | });
|
355 | });
|