@naivemap/mapbox-gl-image-layer 0.5.0 → 0.6.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/es/ImageLayer.js +232 -0
  2. package/dist/es/arrugator/Arrugator.js +270 -0
  3. package/dist/es/{utils/arrugator.js → arrugator/index.js} +43 -39
  4. package/dist/es/index.js +2 -228
  5. package/dist/es/shaders/image.fragment.glsl.js +1 -1
  6. package/dist/es/shaders/image.vertex.glsl.js +1 -1
  7. package/dist/es/shaders/mask.fragment.glsl.js +1 -1
  8. package/dist/es/shaders/mask.vertex.glsl.js +1 -1
  9. package/dist/js/ImageLayer.d.ts +62 -0
  10. package/dist/js/ImageLayer.js +270 -0
  11. package/dist/js/arrugator/Arrugator.d.ts +18 -0
  12. package/dist/js/arrugator/Arrugator.js +275 -0
  13. package/dist/js/arrugator/index.d.ts +7 -0
  14. package/dist/js/{utils/arrugator.js → arrugator/index.js} +49 -46
  15. package/dist/js/index.d.ts +4 -60
  16. package/dist/js/index.js +7 -256
  17. package/dist/js/shaders/image.fragment.glsl.d.ts +2 -2
  18. package/dist/js/shaders/image.fragment.glsl.js +3 -3
  19. package/dist/js/shaders/image.vertex.glsl.d.ts +2 -2
  20. package/dist/js/shaders/image.vertex.glsl.js +3 -3
  21. package/dist/js/shaders/mask.fragment.glsl.d.ts +2 -2
  22. package/dist/js/shaders/mask.fragment.glsl.js +3 -3
  23. package/dist/js/shaders/mask.vertex.glsl.d.ts +2 -2
  24. package/dist/js/shaders/mask.vertex.glsl.js +3 -3
  25. package/package.json +8 -9
  26. package/LICENSE +0 -21
  27. package/dist/es/utils/image.js +0 -19
  28. package/dist/es/utils/webgl.js +0 -64
  29. package/dist/js/utils/arrugator.d.ts +0 -7
  30. package/dist/js/utils/image.d.ts +0 -7
  31. package/dist/js/utils/image.js +0 -23
  32. package/dist/js/utils/webgl.d.ts +0 -8
  33. package/dist/js/utils/webgl.js +0 -68
@@ -0,0 +1,232 @@
1
+ import { satisfies } from 'compare-versions';
2
+ import earcut, { flatten } from 'earcut';
3
+ import mapboxgl from 'mapbox-gl';
4
+ import * as twgl from 'twgl.js';
5
+ import { initArrugator } from './arrugator';
6
+ import fs from './shaders/image.fragment.glsl';
7
+ import vs from './shaders/image.vertex.glsl';
8
+ import maskfs from './shaders/mask.fragment.glsl';
9
+ import maskvs from './shaders/mask.vertex.glsl';
10
+ var ImageLayer = /** @class */ (function () {
11
+ function ImageLayer(id, option) {
12
+ this.type = 'custom';
13
+ this.renderingMode = '2d';
14
+ // mask
15
+ this.stencilChecked = true; // resetStencilClippingMasks 版本检查
16
+ this.id = id;
17
+ this.option = option;
18
+ this.loaded = false;
19
+ this.maskProperty = Object.assign({ type: 'in' }, option.mask);
20
+ this.metadata = option.metadata;
21
+ // 检查 stencil 是否可用
22
+ this.stencilChecked = satisfies(mapboxgl.version, '>=2.7.0');
23
+ // 如果传了 mask 边界数据,且版本不符
24
+ if (this.maskProperty.data && !this.stencilChecked) {
25
+ throw new Error("\u5982\u679C\u9700\u8981\u906E\u7F69\uFF08\u63A9\u819C\uFF09\uFF0Cmapbox-gl \u7248\u672C\u5FC5\u987B\uFF1A>=2.7.0");
26
+ }
27
+ // 初始化 Arrugator
28
+ var projection = option.projection, coordinates = option.coordinates;
29
+ this.arrugado = initArrugator(projection, coordinates, option.arrugatorStep);
30
+ }
31
+ ImageLayer.prototype.onAdd = function (map, gl) {
32
+ this.map = map;
33
+ this.gl = gl;
34
+ // 主程序
35
+ this.programInfo = twgl.createProgramInfo(gl, [vs, fs]);
36
+ this.loadTexture(map, gl);
37
+ this.bufferInfo = twgl.createBufferInfoFromArrays(gl, {
38
+ a_pos: { numComponents: 2, data: this.arrugado.pos },
39
+ a_uv: { numComponents: 2, data: this.arrugado.uv },
40
+ indices: this.arrugado.trigs,
41
+ });
42
+ // 掩膜程序
43
+ if (this.maskProperty.data) {
44
+ var data = this.maskProperty.data;
45
+ if (data) {
46
+ this.maskProgramInfo = twgl.createProgramInfo(gl, [maskvs, maskfs]);
47
+ this.maskBufferInfo = this.getMaskBufferInfo(gl, data);
48
+ }
49
+ }
50
+ };
51
+ ImageLayer.prototype.onRemove = function (_, gl) {
52
+ if (this.programInfo) {
53
+ gl.deleteProgram(this.programInfo.program);
54
+ }
55
+ if (this.maskProgramInfo) {
56
+ gl.deleteProgram(this.maskProgramInfo.program);
57
+ }
58
+ if (this.texture) {
59
+ gl.deleteTexture(this.texture);
60
+ }
61
+ };
62
+ ImageLayer.prototype.render = function (gl, matrix) {
63
+ /**
64
+ * 线图层在启用 stencil 会消失,参考: https://github.com/mapbox/mapbox-gl-js/issues/12213
65
+ * 临时解决方案: map.painter.resetStencilClippingMasks()
66
+ * 该方法在 mapboxgl version >=2.7.0 才能用
67
+ */
68
+ var _a, _b;
69
+ if (this.stencilChecked) {
70
+ // @ts-ignore
71
+ this.map.painter.resetStencilClippingMasks();
72
+ }
73
+ if (this.loaded && this.programInfo && this.bufferInfo) {
74
+ // blend
75
+ gl.enable(gl.BLEND);
76
+ gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
77
+ if (this.maskProgramInfo && this.maskBufferInfo) {
78
+ // mask program
79
+ gl.useProgram(this.maskProgramInfo.program);
80
+ // stencil test
81
+ gl.enable(gl.STENCIL_TEST);
82
+ gl.stencilFunc(gl.ALWAYS, 1, 0xff);
83
+ gl.stencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE);
84
+ gl.stencilMask(0xff);
85
+ gl.clear(gl.STENCIL_BUFFER_BIT);
86
+ // matrix
87
+ twgl.setUniforms(this.maskProgramInfo, { u_matrix: matrix });
88
+ // pos & indices
89
+ twgl.setBuffersAndAttributes(gl, this.maskProgramInfo, this.maskBufferInfo);
90
+ // draw
91
+ var elementType = gl.UNSIGNED_SHORT;
92
+ if (this.maskBufferInfo.numElements / 3 > 65535) {
93
+ // 使 drawElements 支持 UNSIGNED_INT 类型
94
+ gl.getExtension('OES_element_index_uint');
95
+ elementType = gl.UNSIGNED_INT;
96
+ }
97
+ gl.drawElements(gl.TRIANGLES, this.maskBufferInfo.numElements, elementType, 0);
98
+ }
99
+ // texture program
100
+ gl.useProgram(this.programInfo.program);
101
+ if ((_a = this.maskProgramInfo) === null || _a === void 0 ? void 0 : _a.program) {
102
+ // stencil test
103
+ var ref = this.maskProperty.type === 'out' ? 0 : 1;
104
+ gl.stencilFunc(gl.EQUAL, ref, 0xff);
105
+ gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
106
+ }
107
+ // uniforms
108
+ twgl.setUniforms(this.programInfo, {
109
+ u_matrix: matrix,
110
+ u_opacity: (_b = this.option.opacity) !== null && _b !== void 0 ? _b : 1,
111
+ u_sampler: this.texture,
112
+ });
113
+ // pos, uv & indices
114
+ twgl.setBuffersAndAttributes(gl, this.programInfo, this.bufferInfo);
115
+ // draw
116
+ gl.drawElements(gl.TRIANGLES, this.arrugado.trigs.length, gl.UNSIGNED_SHORT, 0);
117
+ gl.clear(gl.STENCIL_BUFFER_BIT);
118
+ gl.disable(gl.STENCIL_TEST);
119
+ }
120
+ };
121
+ /**
122
+ * Updates the URL, the projection, the coordinates, the opacity or the resampling of the image.
123
+ * @param {Object} option Options object.
124
+ * @param {string} [option.url] Image URL.
125
+ * @param {string} [option.projection] Projection with EPSG code that points to the image..
126
+ * @param {Array<Array<number>>} [option.coordinates] Four geographical coordinates,
127
+ * @param {number} [option.opacity] opacity of the image.
128
+ * @param {string} [option.resampling] The resampling/interpolation method to use for overscaling.
129
+ */
130
+ ImageLayer.prototype.updateImage = function (option) {
131
+ var _a, _b, _c, _d, _e;
132
+ if (this.gl && this.map) {
133
+ this.option.opacity = (_a = option.opacity) !== null && _a !== void 0 ? _a : this.option.opacity;
134
+ if (option.projection || option.coordinates) {
135
+ this.option.projection = (_b = option.projection) !== null && _b !== void 0 ? _b : this.option.projection;
136
+ this.option.coordinates = (_c = option.coordinates) !== null && _c !== void 0 ? _c : this.option.coordinates;
137
+ // reinit arrugator
138
+ this.arrugado = initArrugator(this.option.projection, this.option.coordinates, this.option.arrugatorStep);
139
+ this.bufferInfo = twgl.createBufferInfoFromArrays(this.gl, {
140
+ a_pos: { numComponents: 2, data: this.arrugado.pos },
141
+ a_uv: { numComponents: 2, data: this.arrugado.uv },
142
+ indices: this.arrugado.trigs,
143
+ });
144
+ }
145
+ if (option.url || option.resampling) {
146
+ this.loaded = false;
147
+ this.option.url = (_d = option.url) !== null && _d !== void 0 ? _d : this.option.url;
148
+ this.option.resampling = (_e = option.resampling) !== null && _e !== void 0 ? _e : this.option.resampling;
149
+ // reload image
150
+ this.loadTexture(this.map, this.gl);
151
+ }
152
+ else {
153
+ this.map.triggerRepaint();
154
+ }
155
+ }
156
+ return this;
157
+ };
158
+ /**
159
+ * Updates the mask property
160
+ * @param {MaskProperty} mask The mask property.
161
+ */
162
+ ImageLayer.prototype.updateMask = function (mask) {
163
+ if (this.gl && this.map) {
164
+ if (mask.data) {
165
+ if (!this.maskProgramInfo) {
166
+ this.maskProgramInfo = twgl.createProgramInfo(this.gl, [maskvs, maskfs]);
167
+ }
168
+ this.maskProperty = Object.assign(this.maskProperty, mask);
169
+ this.maskBufferInfo = this.getMaskBufferInfo(this.gl, this.maskProperty.data);
170
+ }
171
+ else {
172
+ this.maskProgramInfo && this.gl.deleteProgram(this.maskProgramInfo.program);
173
+ this.maskProgramInfo = undefined;
174
+ this.maskBufferInfo = undefined;
175
+ }
176
+ this.map.triggerRepaint();
177
+ }
178
+ return this;
179
+ };
180
+ ImageLayer.prototype.loadTexture = function (map, gl) {
181
+ var _this = this;
182
+ // 创建纹理
183
+ var filter = this.option.resampling === 'nearest' ? gl.NEAREST : gl.LINEAR;
184
+ this.texture = twgl.createTexture(gl, {
185
+ src: this.option.url,
186
+ crossOrigin: this.option.crossOrigin,
187
+ minMag: filter,
188
+ flipY: 0,
189
+ }, function () {
190
+ _this.loaded = true;
191
+ map.triggerRepaint();
192
+ });
193
+ };
194
+ ImageLayer.prototype.getMaskBufferInfo = function (gl, data) {
195
+ var positions = [];
196
+ var triangles = [];
197
+ if (data.type === 'MultiPolygon') {
198
+ // type: 'MultiPolygon'
199
+ var polyCount = data.coordinates.length;
200
+ var triangleStartIndex_1 = 0;
201
+ for (var i = 0; i < polyCount; i++) {
202
+ var coordinates = data.coordinates[i];
203
+ var flattened = flatten(coordinates);
204
+ var vertices = flattened.vertices, holes = flattened.holes, dimensions = flattened.dimensions;
205
+ var triangle = earcut(vertices, holes, dimensions);
206
+ var triangleNew = triangle.map(function (item) { return item + triangleStartIndex_1; });
207
+ triangleStartIndex_1 += vertices.length / 2;
208
+ // positions.push(...vertices)
209
+ // triangles.push(...triangleNew)
210
+ for (var m = 0; m < vertices.length; m++) {
211
+ positions.push(vertices[m]);
212
+ }
213
+ for (var n = 0; n < triangleNew.length; n++) {
214
+ triangles.push(triangleNew[n]);
215
+ }
216
+ }
217
+ }
218
+ else {
219
+ // type: 'Polygon'
220
+ var flattened = flatten(data.coordinates);
221
+ var vertices = flattened.vertices, holes = flattened.holes, dimensions = flattened.dimensions;
222
+ positions = vertices;
223
+ triangles = earcut(vertices, holes, dimensions);
224
+ }
225
+ return twgl.createBufferInfoFromArrays(gl, {
226
+ a_pos: { numComponents: 2, data: positions },
227
+ indices: triangles.length / 3 > 65535 ? new Uint32Array(triangles) : new Uint16Array(triangles),
228
+ });
229
+ };
230
+ return ImageLayer;
231
+ }());
232
+ export default ImageLayer;
@@ -0,0 +1,270 @@
1
+ /* eslint-disable guard-for-in */
2
+ // @ts-nocheck
3
+ import TinyQueue from 'tinyqueue';
4
+ var Arrugator = /** @class */ (function () {
5
+ function Arrugator(projector, verts, uv, trigs) {
6
+ this._stepsWithSameEpsilon = 0;
7
+ // The projector function. Must be able to take
8
+ // an array of two numbers [x,y] and return an array of
9
+ // two numbers.
10
+ // The typical use case is a proj4(from,to).forward function.
11
+ this._projector = projector;
12
+ // A two-dimensional array of vertex coordinates. Each vertex is a
13
+ // two-element [x,y] array.
14
+ this._verts = verts;
15
+ // A two-dimensional array of UV-map coordinates. These are intended to
16
+ // represent the [0,0]-[1-1] coordinate space of WebGL textures. Each
17
+ // n-th element is the UV coordinates of the n-th vertex. These shall
18
+ // be linearly interpolated when splitting segments.
19
+ this._uv = uv;
20
+ // A two-dimensional array of vertex coordinates, projected. Each
21
+ // vertex is a two-element [x,y] array.
22
+ this._projVerts = verts.map(projector);
23
+ // A two-dimensional array of triangle vertex IDs. Each triangle is a
24
+ // three-element [v1,v2,v3] array.
25
+ // The mesh is **expected** to be compact, planar, non-overlapping.
26
+ this._trigs = trigs;
27
+ // A map of segments to vertices. Key is the segment index (generated inside
28
+ // arrugator), value is an array of two vertex indices.
29
+ this._segs = [];
30
+ this._segCount = 0;
31
+ // A map of segments to triangles. Key is the segment index (generated inside
32
+ // arrugator), value is an array of triangle indices (all segments should
33
+ // have either 1 or 2 triangles associated)
34
+ this._segTrigs = [];
35
+ // A priority queue of segments, ordered by their epsilons, in descending order.
36
+ this._queue = new TinyQueue([], function (a, b) {
37
+ return b.epsilon - a.epsilon;
38
+ });
39
+ // A map of vertex indices to segment indices.
40
+ this._vertToSeg = new Array(verts.length);
41
+ for (var i in this._verts) {
42
+ this._vertToSeg[i] = [];
43
+ }
44
+ /// NOTE: Not using .fill([]), because that would use a reference to the *same*
45
+ /// empty array for every element.
46
+ for (var t in this._trigs) {
47
+ var trig = this._trigs[t];
48
+ var v0 = trig[0];
49
+ var v1 = trig[1];
50
+ var v2 = trig[2];
51
+ this._segment(v0, v1, t);
52
+ this._segment(v1, v2, t);
53
+ this._segment(v2, v0, t);
54
+ }
55
+ }
56
+ // Returns the segment index linking the two given vertex indices;
57
+ // Must be passed a triangle index to use as context.
58
+ // Might create a new segment index (as well as segment data structure and
59
+ // entry in the priority queue).
60
+ Arrugator.prototype._segment = function (v1, v2, t, maxEpsilon) {
61
+ if (maxEpsilon === void 0) { maxEpsilon = Infinity; }
62
+ if (this._vertToSeg[v1] && this._vertToSeg[v1][v2] !== undefined) {
63
+ var found = this._vertToSeg[v1][v2];
64
+ if (!this._segTrigs[found].includes(t)) {
65
+ this._segTrigs[found].push(t);
66
+ }
67
+ return found;
68
+ }
69
+ var segIdx = this._segCount++;
70
+ this._segs[segIdx] = [v1, v2];
71
+ this._vertToSeg[v1][v2] = segIdx;
72
+ this._vertToSeg[v2][v1] = segIdx;
73
+ this._segTrigs[segIdx] = [t];
74
+ // Calculate segment epsilon
75
+ // The "epsilon" of a segment is the square of the midpoint projection distance:
76
+ // i.e. the square of the distance between:
77
+ // - the projected midpoint of the two vertices, and
78
+ // - the midpoint of the two projected vertices,
79
+ // the distance function being euclidean distance in the "destination"
80
+ // projection, squared.
81
+ var midpoint = [
82
+ (this._verts[v1][0] + this._verts[v2][0]) / 2,
83
+ (this._verts[v1][1] + this._verts[v2][1]) / 2,
84
+ ];
85
+ var projectedMid = this._projector(midpoint);
86
+ var midProjected = [
87
+ (this._projVerts[v1][0] + this._projVerts[v2][0]) / 2,
88
+ (this._projVerts[v1][1] + this._projVerts[v2][1]) / 2,
89
+ ];
90
+ var epsilon = Math.pow((projectedMid[0] - midProjected[0]), 2) + Math.pow((projectedMid[1] - midProjected[1]), 2);
91
+ if (Number.isFinite(epsilon) && epsilon < maxEpsilon) {
92
+ this._queue.push({
93
+ v1: v1,
94
+ v2: v2,
95
+ epsilon: epsilon,
96
+ midpoint: midpoint,
97
+ projectedMid: projectedMid,
98
+ });
99
+ }
100
+ return segIdx;
101
+ };
102
+ // Outputs shallow copies of some data structures at the current step.
103
+ Arrugator.prototype.output = function () {
104
+ // Most data structs are 2-dimensional arrays, and doing a shallow copy
105
+ // of the first level *should* just work.
106
+ return {
107
+ unprojected: Array.from(this._verts),
108
+ projected: Array.from(this._projVerts),
109
+ uv: Array.from(this._uv),
110
+ trigs: Array.from(this._trigs),
111
+ };
112
+ };
113
+ // Subdivides the mesh until the maximum segment epsilon is below the
114
+ // given threshold.
115
+ // The `targetEpsilon` parameter must be in the same units as the
116
+ // internal epsilons: units of the projected CRS, **squared**.
117
+ Arrugator.prototype.lowerEpsilon = function (targetEpsilon) {
118
+ var currentEpsilon = this._queue.peek().epsilon;
119
+ var lastEpsilon = currentEpsilon;
120
+ while (currentEpsilon >= targetEpsilon) {
121
+ this.step();
122
+ currentEpsilon = this._queue.peek().epsilon;
123
+ if (currentEpsilon === lastEpsilon) {
124
+ this._stepsWithSameEpsilon++;
125
+ if (this._stepsWithSameEpsilon < 500) {
126
+ console.warn('Arrugator stopped due to epsilon stall. Raster may need hints for proper arrugation.');
127
+ break;
128
+ }
129
+ }
130
+ else {
131
+ this._stepsWithSameEpsilon = 0;
132
+ lastEpsilon = currentEpsilon;
133
+ }
134
+ }
135
+ };
136
+ Object.defineProperty(Arrugator.prototype, "epsilon", {
137
+ get: function () {
138
+ return this._queue.peek().epsilon;
139
+ },
140
+ set: function (ep) {
141
+ return this.lowerEpsilon(ep);
142
+ },
143
+ enumerable: false,
144
+ configurable: true
145
+ });
146
+ // Triggers subdivision of the segment with the largest epsilon.
147
+ Arrugator.prototype.step = function () {
148
+ var seg = this._queue.pop();
149
+ return this._splitSegment(seg, seg.epsilon);
150
+ };
151
+ // Triggers *one* subdivision of *all* segments in the queue.
152
+ // Can be useful to run this prior to stepping, in order to overcome
153
+ // artefacts
154
+ Arrugator.prototype.force = function () {
155
+ var _this = this;
156
+ var segments = this._queue.data;
157
+ this._queue.data = []; // Empties the queue
158
+ this._queue.length = 0;
159
+ segments.forEach(function (seg) { return _this._splitSegment(seg, Infinity); });
160
+ };
161
+ // Splits the given segment.
162
+ // This deletes the segment, spawns a new vertex at the midpoint, and
163
+ // for each triangle the segment was originally a part of (either 1 or 2),
164
+ // the triangle is divided into two.
165
+ Arrugator.prototype._splitSegment = function (seg, maxEpsilon) {
166
+ // Which are the two vertices affected by the popped segment?
167
+ var v1 = seg.v1;
168
+ var v2 = seg.v2;
169
+ var s = this._vertToSeg[v1] && this._vertToSeg[v1][v2];
170
+ // Which triangle(s) are affected by the popped segment?
171
+ var trigs = this._segTrigs[s];
172
+ // Sanity check
173
+ if (trigs.length >= 3) {
174
+ throw new Error('Somehow a segment is shared by three triangles');
175
+ }
176
+ // Clean up refs
177
+ delete this._segTrigs[s];
178
+ delete this._segs[s];
179
+ delete this._vertToSeg[v1][v2];
180
+ delete this._vertToSeg[v2][v1];
181
+ // What is the vertex ID of the new midpoint vertex?
182
+ var vm = this._verts.length;
183
+ this._projVerts[vm] = seg.projectedMid;
184
+ this._verts[vm] = seg.midpoint;
185
+ this._vertToSeg[vm] = [];
186
+ this._uv[vm] = [
187
+ (this._uv[v1][0] + this._uv[v2][0]) / 2,
188
+ (this._uv[v1][1] + this._uv[v2][1]) / 2,
189
+ ];
190
+ for (var _i = 0, trigs_1 = trigs; _i < trigs_1.length; _i++) {
191
+ var t = trigs_1[_i];
192
+ this._splitTriangle(v1, v2, vm, t, maxEpsilon);
193
+ }
194
+ };
195
+ // Split a triangle in two.
196
+ // Must be given vertex indices of the segment being splitted, the index of the new
197
+ // midpoint vertex, and the triangle index.
198
+ // Shall silently drop any new segments with an epsilon larger than the
199
+ // given one. This means that the segment shall be in the triangle mesh,
200
+ // but will not be queued and therefore not subdivided ever.
201
+ Arrugator.prototype._splitTriangle = function (v1, v2, vm, t, epsilon) {
202
+ if (epsilon === void 0) { epsilon = Infinity; }
203
+ var tvs = this._trigs[t];
204
+ var v3;
205
+ var winding = false;
206
+ // Fetch the ID of the 3rd vertex in the original triangle, and the winding order
207
+ if (tvs[0] === v1 && tvs[1] === v2) {
208
+ v3 = tvs[2];
209
+ winding = true; // A-B-C
210
+ }
211
+ else if (tvs[1] === v1 && tvs[2] === v2) {
212
+ v3 = tvs[0];
213
+ winding = true; // C-A-B
214
+ }
215
+ else if (tvs[2] === v1 && tvs[0] === v2) {
216
+ v3 = tvs[1];
217
+ winding = true; // B-C-A
218
+ }
219
+ else if (tvs[1] === v1 && tvs[0] === v2) {
220
+ v3 = tvs[2];
221
+ winding = false; // B-A-C
222
+ }
223
+ else if (tvs[2] === v1 && tvs[1] === v2) {
224
+ v3 = tvs[0];
225
+ winding = false; // C-B-A
226
+ }
227
+ else if (tvs[0] === v1 && tvs[2] === v2) {
228
+ v3 = tvs[1];
229
+ winding = false; // A-C-B
230
+ }
231
+ else {
232
+ throw new Error('Data structure mishap: could not fetch 3rd vertex used in triangle');
233
+ }
234
+ // Index of the first "half" triangle will be the reused index of the original triangle
235
+ // Index of the second "half" triangle must be allocated at the end of the triangles structure
236
+ var t2 = this._trigs.length;
237
+ if (winding) {
238
+ this._trigs[t] = [v1, vm, v3];
239
+ this._trigs[t2] = [vm, v2, v3];
240
+ }
241
+ else {
242
+ this._trigs[t] = [vm, v1, v3];
243
+ this._trigs[t2] = [v2, vm, v3];
244
+ }
245
+ // Clean up references from old segments
246
+ var s1 = this._vertToSeg[v1] && this._vertToSeg[v1][v2];
247
+ var s2 = this._vertToSeg[v2] && this._vertToSeg[v2][v3];
248
+ var s3 = this._vertToSeg[v3] && this._vertToSeg[v3][v1];
249
+ function filterTrig(i) {
250
+ return i !== t;
251
+ }
252
+ if (s1 !== undefined) {
253
+ this._segTrigs[s1] = this._segTrigs[s1].filter(filterTrig);
254
+ }
255
+ if (s2 !== undefined) {
256
+ this._segTrigs[s2] = this._segTrigs[s2].filter(filterTrig);
257
+ }
258
+ if (s3 !== undefined) {
259
+ this._segTrigs[s3] = this._segTrigs[s3].filter(filterTrig);
260
+ }
261
+ this._segment(v1, vm, t, epsilon);
262
+ this._segment(vm, v3, t, epsilon);
263
+ this._segment(v3, v1, t, epsilon);
264
+ this._segment(v2, vm, t2, epsilon);
265
+ this._segment(vm, v3, t2, epsilon);
266
+ this._segment(v3, v2, t2, epsilon);
267
+ };
268
+ return Arrugator;
269
+ }());
270
+ export default Arrugator;
@@ -1,39 +1,43 @@
1
- // @ts-ignore
2
- import Arrugator from 'arrugator';
3
- import proj4 from 'proj4';
4
- export function initArrugator(fromProj, coordinates) {
5
- // 墨卡托投影的左上角坐标,对应 mapbox 左上角起始坐标 [0,0]
6
- var origin = [-20037508.342789244, 20037508.342789244];
7
- // 坐标转换为 Arrugator 坐标 top-left, top-left, top-left, top-left)
8
- var verts = [coordinates[0], coordinates[3], coordinates[1], coordinates[2]];
9
- // 转换为 EPSG:3857
10
- var projector = proj4(fromProj, 'EPSG:3857').forward;
11
- // 改写坐标转换函数,因为 mapbox 的墨卡托坐标是 0-1,并且对应地理范围与标准 3857 不同
12
- function forward(coors) {
13
- // 墨卡托坐标
14
- var coor_3857 = projector(coors);
15
- // 墨卡托坐标转换到 0-1 区间,origin 对应 mapbox 0 0点
16
- var mapbox_coor1 = Math.abs((coor_3857[0] - origin[0]) / (20037508.342789244 * 2));
17
- var mapbox_coor2 = Math.abs((coor_3857[1] - origin[1]) / (20037508.342789244 * 2));
18
- return [mapbox_coor1, mapbox_coor2];
19
- }
20
- var epsilon = 0.00000000001;
21
- // 纹理uv坐标
22
- var sourceUV = [
23
- [0, 0],
24
- [0, 1],
25
- [1, 0],
26
- [1, 1], // bottom-right
27
- ];
28
- var arrugator = new Arrugator(forward, verts, sourceUV, [
29
- [0, 1, 3],
30
- [0, 3, 2],
31
- ]);
32
- arrugator.lowerEpsilon(epsilon);
33
- var arrugado = arrugator.output();
34
- return {
35
- pos: arrugado.projected.flat(),
36
- uv: arrugado.uv.flat(),
37
- trigs: arrugado.trigs.flat(), // 三角形索引
38
- };
39
- }
1
+ import proj4 from 'proj4';
2
+ import Arrugator from './Arrugator';
3
+ export function initArrugator(fromProj, coordinates, step) {
4
+ if (step === void 0) { step = 100; }
5
+ // 墨卡托投影的左上角坐标,对应 mapbox 左上角起始坐标 [0,0]
6
+ var origin = [-20037508.342789244, 20037508.342789244];
7
+ // 坐标转换为 Arrugator 坐标 top-left, top-left, top-left, top-left)
8
+ var verts = [coordinates[0], coordinates[3], coordinates[1], coordinates[2]];
9
+ // 转换为 EPSG:3857
10
+ var projector = proj4(fromProj, 'EPSG:3857').forward;
11
+ // 改写坐标转换函数,因为 mapbox 的墨卡托坐标是 0-1,并且对应地理范围与标准 3857 不同
12
+ function forward(coors) {
13
+ // 墨卡托坐标
14
+ var coor_3857 = projector(coors);
15
+ // 墨卡托坐标转换到 0-1 区间,origin 对应 mapbox 0 0点
16
+ var mapbox_coor1 = Math.abs((coor_3857[0] - origin[0]) / (20037508.342789244 * 2));
17
+ var mapbox_coor2 = Math.abs((coor_3857[1] - origin[1]) / (20037508.342789244 * 2));
18
+ return [mapbox_coor1, mapbox_coor2];
19
+ }
20
+ // 纹理uv坐标
21
+ var sourceUV = [
22
+ [0, 0], // top-left
23
+ [0, 1], // bottom-left
24
+ [1, 0], // top-right
25
+ [1, 1], // bottom-right
26
+ ];
27
+ var arrugator = new Arrugator(forward, verts, sourceUV, [
28
+ [0, 1, 3],
29
+ [0, 3, 2],
30
+ ]);
31
+ if (step > 0) {
32
+ arrugator.force();
33
+ for (var i = 0; i < step; i++) {
34
+ arrugator.step();
35
+ }
36
+ }
37
+ var arrugado = arrugator.output();
38
+ return {
39
+ pos: arrugado.projected.flat(), // mapbox 墨卡托坐标
40
+ uv: arrugado.uv.flat(), // uv 纹理
41
+ trigs: arrugado.trigs.flat(), // 三角形索引
42
+ };
43
+ }