@maplat/transform 0.3.0 → 0.4.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.
package/src/index.ts CHANGED
@@ -1,382 +1,398 @@
1
- import type { Feature, Polygon, Position } from "geojson";
2
- import booleanPointInPolygon from "@turf/boolean-point-in-polygon";
3
- import { point } from "@turf/helpers";
4
- import { getCoords } from "@turf/invariant";
5
- import { unitCalc, transformArr } from "./geometry.ts";
6
- import type { Tri } from "./geometry.ts";
7
- import {
8
- FORMAT_VERSION,
9
- isModernCompiled,
10
- restoreLegacyState,
11
- restoreModernState
12
- } from "./compiled-state.ts";
13
- import type { EdgeSet } from "./edgeutils.ts";
14
- import type {
15
- Compiled,
16
- CompiledLegacy,
17
- IndexedTinsBD,
18
- KinksBD,
19
- LegacyStatePayload,
20
- ModernStatePayload,
21
- PointSet,
22
- StrictMode,
23
- StrictStatus,
24
- TinsBD,
25
- VertexMode,
26
- VerticesParamsBD,
27
- WeightBufferBD,
28
- YaxisMode,
29
- CentroidBD
30
- } from "./types.ts";
31
- export type {
32
- PointSet,
33
- BiDirectionKey,
34
- WeightBufferBD,
35
- VertexMode,
36
- StrictMode,
37
- StrictStatus,
38
- YaxisMode,
39
- CentroidBD,
40
- TinsBD,
41
- KinksBD,
42
- VerticesParamsBD,
43
- IndexedTinsBD,
44
- Compiled,
45
- CompiledLegacy
46
- } from "./types.ts";
47
- export type { Tins, Tri, PropertyTriKey } from "./geometry.ts";
48
- export { transformArr } from "./geometry.ts";
49
- export { rotateVerticesTriangle, counterTri } from "./triangulation.ts";
50
- export type { Edge, EdgeSet, EdgeSetLegacy } from "./edgeutils.ts";
51
- export { normalizeEdges } from "./edgeutils.ts";
52
- export const format_version = FORMAT_VERSION;
53
-
54
- /**
55
- * 座標変換の基本機能を提供するクラス
56
- *
57
- * 2つの座標系間の変換を、TINネットワークを使用して実現します。
58
- * このクラスは基本的な変換機能のみを提供し、
59
- * 設定ファイルの生成などの追加機能はTinクラスで提供されます。
60
- */
61
- export class Transform {
62
- /**
63
- * 各種モードの定数定義
64
- * すべてreadonlyで、型安全性を確保
65
- */
66
- static VERTEX_PLAIN = "plain" as const;
67
- static VERTEX_BIRDEYE = "birdeye" as const;
68
- static MODE_STRICT = "strict" as const;
69
- static MODE_AUTO = "auto" as const;
70
- static MODE_LOOSE = "loose" as const;
71
- static STATUS_STRICT = "strict" as const;
72
- static STATUS_ERROR = "strict_error" as const;
73
- static STATUS_LOOSE = "loose" as const;
74
- static YAXIS_FOLLOW = "follow" as const;
75
- static YAXIS_INVERT = "invert" as const;
76
-
77
- points: PointSet[] = [];
78
- pointsWeightBuffer?: WeightBufferBD;
79
- strict_status?: StrictStatus;
80
- vertices_params?: VerticesParamsBD;
81
- centroid?: CentroidBD;
82
- edgeNodes?: PointSet[];
83
- edges?: EdgeSet[];
84
- tins?: TinsBD;
85
- kinks?: KinksBD;
86
- yaxisMode: YaxisMode = Transform.YAXIS_INVERT;
87
- strictMode: StrictMode = Transform.MODE_AUTO;
88
- vertexMode?: VertexMode = Transform.VERTEX_PLAIN;
89
- bounds?: number[][];
90
- boundsPolygon?: Feature<Polygon>;
91
- wh?: number[];
92
- xy?: number[];
93
- indexedTins?: IndexedTinsBD;
94
- stateFull = false;
95
- stateTriangle?: Tri;
96
- stateBackward?: boolean;
97
-
98
- constructor() {}
99
-
100
- /**
101
- * コンパイルされた設定を適用します
102
- *
103
- * @param compiled - コンパイルされた設定オブジェクト
104
- * @returns 変換に必要な主要なオブジェクトのセット
105
- *
106
- * 以下の処理を行います:
107
- * 1. バージョンに応じた設定の解釈
108
- * 2. 各種パラメータの復元
109
- * 3. TINネットワークの再構築
110
- * 4. インデックスの作成
111
- */
112
- setCompiled(compiled: Compiled | CompiledLegacy): void {
113
- if (isModernCompiled(compiled)) {
114
- this.applyModernState(restoreModernState(compiled));
115
- return;
116
- }
117
- this.applyLegacyState(restoreLegacyState(compiled as CompiledLegacy));
118
- }
119
-
120
- private applyModernState(state: ModernStatePayload): void {
121
- this.points = state.points;
122
- this.pointsWeightBuffer = state.pointsWeightBuffer;
123
- this.strict_status = state.strictStatus;
124
- this.vertices_params = state.verticesParams;
125
- this.centroid = state.centroid;
126
- this.edges = state.edges;
127
- this.edgeNodes = state.edgeNodes || [];
128
- this.tins = state.tins;
129
- this.addIndexedTin();
130
- this.kinks = state.kinks;
131
- this.yaxisMode = state.yaxisMode ?? Transform.YAXIS_INVERT;
132
- this.vertexMode = state.vertexMode ?? Transform.VERTEX_PLAIN;
133
- this.strictMode = state.strictMode ?? Transform.MODE_AUTO;
134
- if (state.bounds) {
135
- this.bounds = state.bounds;
136
- this.boundsPolygon = state.boundsPolygon;
137
- this.xy = state.xy;
138
- this.wh = state.wh;
139
- } else {
140
- this.bounds = undefined;
141
- this.boundsPolygon = undefined;
142
- this.xy = state.xy ?? [0, 0];
143
- if (state.wh) this.wh = state.wh;
144
- }
145
- }
146
-
147
- private applyLegacyState(state: LegacyStatePayload): void {
148
- this.tins = state.tins;
149
- this.addIndexedTin();
150
- this.strict_status = state.strictStatus;
151
- this.pointsWeightBuffer = state.pointsWeightBuffer;
152
- this.vertices_params = state.verticesParams;
153
- this.centroid = state.centroid;
154
- this.kinks = state.kinks;
155
- this.points = state.points;
156
- }
157
-
158
- /**
159
- * TINネットワークのインデックスを作成します
160
- *
161
- * インデックスは変換処理を高速化するために使用されます。
162
- * グリッド形式のインデックスを作成し、各グリッドに
163
- * 含まれる三角形を記録します。
164
- */
165
- addIndexedTin() {
166
- const tins = this.tins!;
167
- const forw = tins.forw;
168
- const bakw = tins.bakw;
169
- const gridNum = Math.ceil(Math.sqrt(forw!.features.length));
170
- if (gridNum < 3) {
171
- this.indexedTins = undefined;
172
- return;
173
- }
174
- let forwBound: Position[] = [];
175
- let bakwBound: Position[] = [];
176
- const forwEachBound = forw!.features.map((tri: Tri) => {
177
- let eachBound: Position[] = [];
178
- getCoords(tri)[0].map((point: Position) => {
179
- if (forwBound.length === 0)
180
- forwBound = [Array.from(point), Array.from(point)];
181
- else {
182
- if (point[0] < forwBound[0][0]) forwBound[0][0] = point[0];
183
- if (point[0] > forwBound[1][0]) forwBound[1][0] = point[0];
184
- if (point[1] < forwBound[0][1]) forwBound[0][1] = point[1];
185
- if (point[1] > forwBound[1][1]) forwBound[1][1] = point[1];
186
- }
187
- if (eachBound.length === 0)
188
- eachBound = [Array.from(point), Array.from(point)];
189
- else {
190
- if (point[0] < eachBound[0][0]) eachBound[0][0] = point[0];
191
- if (point[0] > eachBound[1][0]) eachBound[1][0] = point[0];
192
- if (point[1] < eachBound[0][1]) eachBound[0][1] = point[1];
193
- if (point[1] > eachBound[1][1]) eachBound[1][1] = point[1];
194
- }
195
- });
196
- return eachBound;
197
- });
198
- const forwXUnit = (forwBound[1][0] - forwBound[0][0]) / gridNum;
199
- const forwYUnit = (forwBound[1][1] - forwBound[0][1]) / gridNum;
200
- const forwGridCache = forwEachBound.reduce(
201
- (prev: number[][][], bound: Position[], index: number) => {
202
- const normXMin = unitCalc(
203
- bound[0][0],
204
- forwBound[0][0],
205
- forwXUnit,
206
- gridNum
207
- );
208
- const normXMax = unitCalc(
209
- bound[1][0],
210
- forwBound[0][0],
211
- forwXUnit,
212
- gridNum
213
- );
214
- const normYMin = unitCalc(
215
- bound[0][1],
216
- forwBound[0][1],
217
- forwYUnit,
218
- gridNum
219
- );
220
- const normYMax = unitCalc(
221
- bound[1][1],
222
- forwBound[0][1],
223
- forwYUnit,
224
- gridNum
225
- );
226
- for (let cx = normXMin; cx <= normXMax; cx++) {
227
- if (!prev[cx]) prev[cx] = [];
228
- for (let cy = normYMin; cy <= normYMax; cy++) {
229
- if (!prev[cx][cy]) prev[cx][cy] = [];
230
- prev[cx][cy].push(index);
231
- }
232
- }
233
- return prev;
234
- },
235
- []
236
- );
237
- const bakwEachBound = bakw!.features.map((tri: Tri) => {
238
- let eachBound: Position[] = [];
239
- getCoords(tri)[0].map((point: Position) => {
240
- if (bakwBound.length === 0)
241
- bakwBound = [Array.from(point), Array.from(point)];
242
- else {
243
- if (point[0] < bakwBound[0][0]) bakwBound[0][0] = point[0];
244
- if (point[0] > bakwBound[1][0]) bakwBound[1][0] = point[0];
245
- if (point[1] < bakwBound[0][1]) bakwBound[0][1] = point[1];
246
- if (point[1] > bakwBound[1][1]) bakwBound[1][1] = point[1];
247
- }
248
- if (eachBound.length === 0)
249
- eachBound = [Array.from(point), Array.from(point)];
250
- else {
251
- if (point[0] < eachBound[0][0]) eachBound[0][0] = point[0];
252
- if (point[0] > eachBound[1][0]) eachBound[1][0] = point[0];
253
- if (point[1] < eachBound[0][1]) eachBound[0][1] = point[1];
254
- if (point[1] > eachBound[1][1]) eachBound[1][1] = point[1];
255
- }
256
- });
257
- return eachBound;
258
- });
259
- const bakwXUnit = (bakwBound[1][0] - bakwBound[0][0]) / gridNum;
260
- const bakwYUnit = (bakwBound[1][1] - bakwBound[0][1]) / gridNum;
261
- const bakwGridCache = bakwEachBound.reduce(
262
- (prev: number[][][], bound: Position[], index: number) => {
263
- const normXMin = unitCalc(
264
- bound[0][0],
265
- bakwBound[0][0],
266
- bakwXUnit,
267
- gridNum
268
- );
269
- const normXMax = unitCalc(
270
- bound[1][0],
271
- bakwBound[0][0],
272
- bakwXUnit,
273
- gridNum
274
- );
275
- const normYMin = unitCalc(
276
- bound[0][1],
277
- bakwBound[0][1],
278
- bakwYUnit,
279
- gridNum
280
- );
281
- const normYMax = unitCalc(
282
- bound[1][1],
283
- bakwBound[0][1],
284
- bakwYUnit,
285
- gridNum
286
- );
287
- for (let cx = normXMin; cx <= normXMax; cx++) {
288
- if (!prev[cx]) prev[cx] = [];
289
- for (let cy = normYMin; cy <= normYMax; cy++) {
290
- if (!prev[cx][cy]) prev[cx][cy] = [];
291
- prev[cx][cy].push(index);
292
- }
293
- }
294
- return prev;
295
- },
296
- []
297
- );
298
- this.indexedTins = {
299
- forw: {
300
- gridNum,
301
- xOrigin: forwBound[0][0],
302
- yOrigin: forwBound[0][1],
303
- xUnit: forwXUnit,
304
- yUnit: forwYUnit,
305
- gridCache: forwGridCache
306
- },
307
- bakw: {
308
- gridNum,
309
- xOrigin: bakwBound[0][0],
310
- yOrigin: bakwBound[0][1],
311
- xUnit: bakwXUnit,
312
- yUnit: bakwYUnit,
313
- gridCache: bakwGridCache
314
- }
315
- };
316
- }
317
-
318
- /**
319
- * 座標変換を実行します
320
- *
321
- * @param apoint - 変換する座標
322
- * @param backward - 逆方向の変換かどうか
323
- * @param ignoreBounds - 境界チェックを無視するかどうか
324
- * @returns 変換後の座標、または境界外の場合はfalse
325
- *
326
- * @throws {Error} 逆方向変換が許可されていない状態での逆変換時
327
- */
328
- transform(apoint: number[], backward?: boolean, ignoreBounds?: boolean): number[] | false {
329
- if (backward && this.strict_status == Transform.STATUS_ERROR)
330
- throw 'Backward transform is not allowed if strict_status == "strict_error"';
331
- // if (!this.tins) this.updateTin();
332
- if (this.yaxisMode == Transform.YAXIS_FOLLOW && backward) {
333
- apoint = [apoint[0], -1 * apoint[1]];
334
- }
335
- const tpoint = point(apoint);
336
- if (this.bounds && !backward && !ignoreBounds) {
337
- if (!booleanPointInPolygon(tpoint, this.boundsPolygon!)) return false;
338
- }
339
- const tins = backward ? this.tins!.bakw : this.tins!.forw;
340
- const indexedTins = backward
341
- ? this.indexedTins!.bakw
342
- : this.indexedTins!.forw;
343
- const verticesParams = backward
344
- ? this.vertices_params!.bakw
345
- : this.vertices_params!.forw;
346
- const centroid = backward ? this.centroid!.bakw : this.centroid!.forw;
347
- const weightBuffer = backward
348
- ? this.pointsWeightBuffer!.bakw
349
- : this.pointsWeightBuffer!.forw;
350
- let stateTriangle = undefined,
351
- stateSetFunc = undefined;
352
- if (this.stateFull) {
353
- if (this.stateBackward == backward) {
354
- stateTriangle = this.stateTriangle;
355
- } else {
356
- this.stateBackward = backward;
357
- this.stateTriangle = undefined;
358
- }
359
- stateSetFunc = (tri?: Tri) => {
360
- this.stateTriangle = tri;
361
- };
362
- }
363
- let ret = transformArr(
364
- tpoint,
365
- tins!,
366
- indexedTins,
367
- verticesParams,
368
- centroid,
369
- weightBuffer,
370
- stateTriangle,
371
- stateSetFunc
372
- );
373
- if (this.bounds && backward && !ignoreBounds) {
374
- const rpoint = point(ret);
375
- if (!booleanPointInPolygon(rpoint, this.boundsPolygon!)) return false;
376
- } else if (this.yaxisMode == Transform.YAXIS_FOLLOW && !backward) {
377
- ret = [ret[0], -1 * ret[1]];
378
- }
379
- return ret;
380
- }
381
-
382
- }
1
+ import type { Feature, Polygon, Position } from "geojson";
2
+ import { booleanPointInPolygon, point, getCoords } from "@turf/turf";
3
+ import { unitCalc, transformArr } from "./geometry.ts";
4
+ import type { Tri } from "./geometry.ts";
5
+ import {
6
+ FORMAT_VERSION,
7
+ isModernCompiled,
8
+ restoreLegacyState,
9
+ restoreModernState
10
+ } from "./compiled-state.ts";
11
+ import type { EdgeSet } from "./edgeutils.ts";
12
+ import type {
13
+ Compiled,
14
+ CompiledLegacy,
15
+ IndexedTinsBD,
16
+ KinksBD,
17
+ LegacyStatePayload,
18
+ ModernStatePayload,
19
+ PointSet,
20
+ StrictMode,
21
+ StrictStatus,
22
+ TinsBD,
23
+ VertexMode,
24
+ VerticesParamsBD,
25
+ WeightBufferBD,
26
+ YaxisMode,
27
+ CentroidBD
28
+ } from "./types.ts";
29
+ export type {
30
+ PointSet,
31
+ BiDirectionKey,
32
+ WeightBufferBD,
33
+ VertexMode,
34
+ StrictMode,
35
+ StrictStatus,
36
+ YaxisMode,
37
+ CentroidBD,
38
+ TinsBD,
39
+ KinksBD,
40
+ VerticesParamsBD,
41
+ IndexedTinsBD,
42
+ Compiled,
43
+ CompiledLegacy
44
+ } from "./types.ts";
45
+ export type { Tins, Tri, PropertyTriKey } from "./geometry.ts";
46
+ export { transformArr } from "./geometry.ts";
47
+ export { rotateVerticesTriangle, counterTri } from "./triangulation.ts";
48
+ export type { Edge, EdgeSet, EdgeSetLegacy } from "./edgeutils.ts";
49
+ export { normalizeEdges } from "./edgeutils.ts";
50
+ export const format_version = FORMAT_VERSION;
51
+
52
+ /**
53
+ * 座標変換の基本機能を提供するクラス
54
+ *
55
+ * 2つの座標系間の変換を、TINネットワークを使用して実現します。
56
+ * このクラスは基本的な変換機能のみを提供し、
57
+ * 設定ファイルの生成などの追加機能はTinクラスで提供されます。
58
+ */
59
+ export class Transform {
60
+ /**
61
+ * 各種モードの定数定義
62
+ * すべてreadonlyで、型安全性を確保
63
+ */
64
+ static VERTEX_PLAIN = "plain" as const;
65
+ static VERTEX_BIRDEYE = "birdeye" as const;
66
+ static MODE_STRICT = "strict" as const;
67
+ static MODE_AUTO = "auto" as const;
68
+ static MODE_LOOSE = "loose" as const;
69
+ static STATUS_STRICT = "strict" as const;
70
+ static STATUS_ERROR = "strict_error" as const;
71
+ static STATUS_LOOSE = "loose" as const;
72
+ static YAXIS_FOLLOW = "follow" as const;
73
+ static YAXIS_INVERT = "invert" as const;
74
+
75
+ points: PointSet[] = [];
76
+ pointsWeightBuffer?: WeightBufferBD;
77
+ strict_status?: StrictStatus;
78
+ vertices_params?: VerticesParamsBD;
79
+ centroid?: CentroidBD;
80
+ edgeNodes?: PointSet[];
81
+ edges?: EdgeSet[];
82
+ tins?: TinsBD;
83
+ kinks?: KinksBD;
84
+ yaxisMode: YaxisMode = Transform.YAXIS_INVERT;
85
+ strictMode: StrictMode = Transform.MODE_AUTO;
86
+ vertexMode?: VertexMode = Transform.VERTEX_PLAIN;
87
+ bounds?: number[][];
88
+ boundsPolygon?: Feature<Polygon>;
89
+ wh?: number[];
90
+ xy?: number[];
91
+ indexedTins?: IndexedTinsBD;
92
+ stateFull = false;
93
+ stateTriangle?: Tri;
94
+ stateBackward?: boolean;
95
+
96
+ /**
97
+ * Optional properties for MaplatCore extension
98
+ * These properties allow consuming applications to extend Transform instances
99
+ * with additional metadata without requiring Module Augmentation
100
+ */
101
+
102
+ /** Layer priority for rendering order */
103
+ priority?: number;
104
+
105
+ /** Layer importance for display decisions */
106
+ importance?: number;
107
+
108
+ /** Bounds in XY (source) coordinate system */
109
+ xyBounds?: Feature<Polygon>;
110
+
111
+ /** Bounds in Mercator (Web Mercator) coordinate system */
112
+ mercBounds?: Feature<Polygon>;
113
+
114
+ constructor() { }
115
+
116
+ /**
117
+ * コンパイルされた設定を適用します
118
+ *
119
+ * @param compiled - コンパイルされた設定オブジェクト
120
+ * @returns 変換に必要な主要なオブジェクトのセット
121
+ *
122
+ * 以下の処理を行います:
123
+ * 1. バージョンに応じた設定の解釈
124
+ * 2. 各種パラメータの復元
125
+ * 3. TINネットワークの再構築
126
+ * 4. インデックスの作成
127
+ */
128
+ setCompiled(compiled: Compiled | CompiledLegacy): void {
129
+ if (isModernCompiled(compiled)) {
130
+ this.applyModernState(restoreModernState(compiled));
131
+ return;
132
+ }
133
+ this.applyLegacyState(restoreLegacyState(compiled as CompiledLegacy));
134
+ }
135
+
136
+ private applyModernState(state: ModernStatePayload): void {
137
+ this.points = state.points;
138
+ this.pointsWeightBuffer = state.pointsWeightBuffer;
139
+ this.strict_status = state.strictStatus;
140
+ this.vertices_params = state.verticesParams;
141
+ this.centroid = state.centroid;
142
+ this.edges = state.edges;
143
+ this.edgeNodes = state.edgeNodes || [];
144
+ this.tins = state.tins;
145
+ this.addIndexedTin();
146
+ this.kinks = state.kinks;
147
+ this.yaxisMode = state.yaxisMode ?? Transform.YAXIS_INVERT;
148
+ this.vertexMode = state.vertexMode ?? Transform.VERTEX_PLAIN;
149
+ this.strictMode = state.strictMode ?? Transform.MODE_AUTO;
150
+ if (state.bounds) {
151
+ this.bounds = state.bounds;
152
+ this.boundsPolygon = state.boundsPolygon;
153
+ this.xy = state.xy;
154
+ this.wh = state.wh;
155
+ } else {
156
+ this.bounds = undefined;
157
+ this.boundsPolygon = undefined;
158
+ this.xy = state.xy ?? [0, 0];
159
+ if (state.wh) this.wh = state.wh;
160
+ }
161
+ }
162
+
163
+ private applyLegacyState(state: LegacyStatePayload): void {
164
+ this.tins = state.tins;
165
+ this.addIndexedTin();
166
+ this.strict_status = state.strictStatus;
167
+ this.pointsWeightBuffer = state.pointsWeightBuffer;
168
+ this.vertices_params = state.verticesParams;
169
+ this.centroid = state.centroid;
170
+ this.kinks = state.kinks;
171
+ this.points = state.points;
172
+ }
173
+
174
+ /**
175
+ * TINネットワークのインデックスを作成します
176
+ *
177
+ * インデックスは変換処理を高速化するために使用されます。
178
+ * グリッド形式のインデックスを作成し、各グリッドに
179
+ * 含まれる三角形を記録します。
180
+ */
181
+ addIndexedTin() {
182
+ const tins = this.tins!;
183
+ const forw = tins.forw;
184
+ const bakw = tins.bakw;
185
+ const gridNum = Math.ceil(Math.sqrt(forw!.features.length));
186
+ if (gridNum < 3) {
187
+ this.indexedTins = undefined;
188
+ return;
189
+ }
190
+ let forwBound: Position[] = [];
191
+ let bakwBound: Position[] = [];
192
+ const forwEachBound = forw!.features.map((tri: Tri) => {
193
+ let eachBound: Position[] = [];
194
+ getCoords(tri)[0].map((point: Position) => {
195
+ if (forwBound.length === 0)
196
+ forwBound = [Array.from(point), Array.from(point)];
197
+ else {
198
+ if (point[0] < forwBound[0][0]) forwBound[0][0] = point[0];
199
+ if (point[0] > forwBound[1][0]) forwBound[1][0] = point[0];
200
+ if (point[1] < forwBound[0][1]) forwBound[0][1] = point[1];
201
+ if (point[1] > forwBound[1][1]) forwBound[1][1] = point[1];
202
+ }
203
+ if (eachBound.length === 0)
204
+ eachBound = [Array.from(point), Array.from(point)];
205
+ else {
206
+ if (point[0] < eachBound[0][0]) eachBound[0][0] = point[0];
207
+ if (point[0] > eachBound[1][0]) eachBound[1][0] = point[0];
208
+ if (point[1] < eachBound[0][1]) eachBound[0][1] = point[1];
209
+ if (point[1] > eachBound[1][1]) eachBound[1][1] = point[1];
210
+ }
211
+ });
212
+ return eachBound;
213
+ });
214
+ const forwXUnit = (forwBound[1][0] - forwBound[0][0]) / gridNum;
215
+ const forwYUnit = (forwBound[1][1] - forwBound[0][1]) / gridNum;
216
+ const forwGridCache = forwEachBound.reduce(
217
+ (prev: number[][][], bound: Position[], index: number) => {
218
+ const normXMin = unitCalc(
219
+ bound[0][0],
220
+ forwBound[0][0],
221
+ forwXUnit,
222
+ gridNum
223
+ );
224
+ const normXMax = unitCalc(
225
+ bound[1][0],
226
+ forwBound[0][0],
227
+ forwXUnit,
228
+ gridNum
229
+ );
230
+ const normYMin = unitCalc(
231
+ bound[0][1],
232
+ forwBound[0][1],
233
+ forwYUnit,
234
+ gridNum
235
+ );
236
+ const normYMax = unitCalc(
237
+ bound[1][1],
238
+ forwBound[0][1],
239
+ forwYUnit,
240
+ gridNum
241
+ );
242
+ for (let cx = normXMin; cx <= normXMax; cx++) {
243
+ if (!prev[cx]) prev[cx] = [];
244
+ for (let cy = normYMin; cy <= normYMax; cy++) {
245
+ if (!prev[cx][cy]) prev[cx][cy] = [];
246
+ prev[cx][cy].push(index);
247
+ }
248
+ }
249
+ return prev;
250
+ },
251
+ []
252
+ );
253
+ const bakwEachBound = bakw!.features.map((tri: Tri) => {
254
+ let eachBound: Position[] = [];
255
+ getCoords(tri)[0].map((point: Position) => {
256
+ if (bakwBound.length === 0)
257
+ bakwBound = [Array.from(point), Array.from(point)];
258
+ else {
259
+ if (point[0] < bakwBound[0][0]) bakwBound[0][0] = point[0];
260
+ if (point[0] > bakwBound[1][0]) bakwBound[1][0] = point[0];
261
+ if (point[1] < bakwBound[0][1]) bakwBound[0][1] = point[1];
262
+ if (point[1] > bakwBound[1][1]) bakwBound[1][1] = point[1];
263
+ }
264
+ if (eachBound.length === 0)
265
+ eachBound = [Array.from(point), Array.from(point)];
266
+ else {
267
+ if (point[0] < eachBound[0][0]) eachBound[0][0] = point[0];
268
+ if (point[0] > eachBound[1][0]) eachBound[1][0] = point[0];
269
+ if (point[1] < eachBound[0][1]) eachBound[0][1] = point[1];
270
+ if (point[1] > eachBound[1][1]) eachBound[1][1] = point[1];
271
+ }
272
+ });
273
+ return eachBound;
274
+ });
275
+ const bakwXUnit = (bakwBound[1][0] - bakwBound[0][0]) / gridNum;
276
+ const bakwYUnit = (bakwBound[1][1] - bakwBound[0][1]) / gridNum;
277
+ const bakwGridCache = bakwEachBound.reduce(
278
+ (prev: number[][][], bound: Position[], index: number) => {
279
+ const normXMin = unitCalc(
280
+ bound[0][0],
281
+ bakwBound[0][0],
282
+ bakwXUnit,
283
+ gridNum
284
+ );
285
+ const normXMax = unitCalc(
286
+ bound[1][0],
287
+ bakwBound[0][0],
288
+ bakwXUnit,
289
+ gridNum
290
+ );
291
+ const normYMin = unitCalc(
292
+ bound[0][1],
293
+ bakwBound[0][1],
294
+ bakwYUnit,
295
+ gridNum
296
+ );
297
+ const normYMax = unitCalc(
298
+ bound[1][1],
299
+ bakwBound[0][1],
300
+ bakwYUnit,
301
+ gridNum
302
+ );
303
+ for (let cx = normXMin; cx <= normXMax; cx++) {
304
+ if (!prev[cx]) prev[cx] = [];
305
+ for (let cy = normYMin; cy <= normYMax; cy++) {
306
+ if (!prev[cx][cy]) prev[cx][cy] = [];
307
+ prev[cx][cy].push(index);
308
+ }
309
+ }
310
+ return prev;
311
+ },
312
+ []
313
+ );
314
+ this.indexedTins = {
315
+ forw: {
316
+ gridNum,
317
+ xOrigin: forwBound[0][0],
318
+ yOrigin: forwBound[0][1],
319
+ xUnit: forwXUnit,
320
+ yUnit: forwYUnit,
321
+ gridCache: forwGridCache
322
+ },
323
+ bakw: {
324
+ gridNum,
325
+ xOrigin: bakwBound[0][0],
326
+ yOrigin: bakwBound[0][1],
327
+ xUnit: bakwXUnit,
328
+ yUnit: bakwYUnit,
329
+ gridCache: bakwGridCache
330
+ }
331
+ };
332
+ }
333
+
334
+ /**
335
+ * 座標変換を実行します
336
+ *
337
+ * @param apoint - 変換する座標
338
+ * @param backward - 逆方向の変換かどうか
339
+ * @param ignoreBounds - 境界チェックを無視するかどうか
340
+ * @returns 変換後の座標、または境界外の場合はfalse
341
+ *
342
+ * @throws {Error} 逆方向変換が許可されていない状態での逆変換時
343
+ */
344
+ transform(apoint: number[], backward?: boolean, ignoreBounds?: boolean): number[] | false {
345
+ if (backward && this.strict_status == Transform.STATUS_ERROR)
346
+ throw 'Backward transform is not allowed if strict_status == "strict_error"';
347
+ // if (!this.tins) this.updateTin();
348
+ if (this.yaxisMode == Transform.YAXIS_FOLLOW && backward) {
349
+ apoint = [apoint[0], -1 * apoint[1]];
350
+ }
351
+ const tpoint = point(apoint);
352
+ if (this.bounds && !backward && !ignoreBounds) {
353
+ if (!booleanPointInPolygon(tpoint, this.boundsPolygon!)) return false;
354
+ }
355
+ const tins = backward ? this.tins!.bakw : this.tins!.forw;
356
+ const indexedTins = backward
357
+ ? this.indexedTins!.bakw
358
+ : this.indexedTins!.forw;
359
+ const verticesParams = backward
360
+ ? this.vertices_params!.bakw
361
+ : this.vertices_params!.forw;
362
+ const centroid = backward ? this.centroid!.bakw : this.centroid!.forw;
363
+ const weightBuffer = backward
364
+ ? this.pointsWeightBuffer!.bakw
365
+ : this.pointsWeightBuffer!.forw;
366
+ let stateTriangle = undefined,
367
+ stateSetFunc = undefined;
368
+ if (this.stateFull) {
369
+ if (this.stateBackward == backward) {
370
+ stateTriangle = this.stateTriangle;
371
+ } else {
372
+ this.stateBackward = backward;
373
+ this.stateTriangle = undefined;
374
+ }
375
+ stateSetFunc = (tri?: Tri) => {
376
+ this.stateTriangle = tri;
377
+ };
378
+ }
379
+ let ret = transformArr(
380
+ tpoint,
381
+ tins!,
382
+ indexedTins,
383
+ verticesParams,
384
+ centroid,
385
+ weightBuffer,
386
+ stateTriangle,
387
+ stateSetFunc
388
+ );
389
+ if (this.bounds && backward && !ignoreBounds) {
390
+ const rpoint = point(ret);
391
+ if (!booleanPointInPolygon(rpoint, this.boundsPolygon!)) return false;
392
+ } else if (this.yaxisMode == Transform.YAXIS_FOLLOW && !backward) {
393
+ ret = [ret[0], -1 * ret[1]];
394
+ }
395
+ return ret;
396
+ }
397
+
398
+ }