@math.gl/geospatial 5.0.0-beta.1 → 5.0.0-beta.2
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/dist/crs/crs-identifier.d.ts +23 -0
- package/dist/crs/crs-identifier.d.ts.map +1 -0
- package/dist/crs/crs-identifier.js +74 -0
- package/dist/crs/crs-identifier.js.map +1 -0
- package/dist/crs/index.cjs +48 -0
- package/dist/crs/index.cjs.map +2 -2
- package/dist/crs/index.d.ts +1 -0
- package/dist/crs/index.d.ts.map +1 -1
- package/dist/crs/index.js +1 -0
- package/dist/crs/index.js.map +1 -1
- package/dist/discontinuous/cap-map.d.ts.map +1 -1
- package/dist/discontinuous/cap-map.js +197 -13
- package/dist/discontinuous/cap-map.js.map +1 -1
- package/dist/discontinuous/elastic/geometry.d.ts +1 -1
- package/dist/discontinuous/elastic/geometry.d.ts.map +1 -1
- package/dist/discontinuous/elastic/geometry.js +7 -7
- package/dist/discontinuous/elastic/geometry.js.map +1 -1
- package/dist/discontinuous/elastic/map.d.ts.map +1 -1
- package/dist/discontinuous/elastic/map.js +263 -23
- package/dist/discontinuous/elastic/map.js.map +1 -1
- package/dist/discontinuous/elastic/source-arc.d.ts +10 -0
- package/dist/discontinuous/elastic/source-arc.d.ts.map +1 -0
- package/dist/discontinuous/elastic/source-arc.js +111 -0
- package/dist/discontinuous/elastic/source-arc.js.map +1 -0
- package/dist/discontinuous/global-polygons.d.ts +1 -1
- package/dist/discontinuous/global-polygons.d.ts.map +1 -1
- package/dist/discontinuous/global-polygons.js +49 -1
- package/dist/discontinuous/global-polygons.js.map +1 -1
- package/dist/discontinuous/map-engine.d.ts +9 -0
- package/dist/discontinuous/map-engine.d.ts.map +1 -1
- package/dist/discontinuous/map-layout.d.ts +21 -0
- package/dist/discontinuous/map-layout.d.ts.map +1 -1
- package/dist/discontinuous/map-layout.js +116 -1
- package/dist/discontinuous/map-layout.js.map +1 -1
- package/dist/discontinuous/map-transition.d.ts.map +1 -1
- package/dist/discontinuous/map-transition.js +66 -3
- package/dist/discontinuous/map-transition.js.map +1 -1
- package/dist/discontinuous/mercator-map.d.ts +2 -2
- package/dist/discontinuous/mercator-map.d.ts.map +1 -1
- package/dist/discontinuous/mercator-map.js +123 -11
- package/dist/discontinuous/mercator-map.js.map +1 -1
- package/dist/discontinuous/polygon-constraints.d.ts +16 -0
- package/dist/discontinuous/polygon-constraints.d.ts.map +1 -0
- package/dist/discontinuous/polygon-constraints.js +157 -0
- package/dist/discontinuous/polygon-constraints.js.map +1 -0
- package/dist/discontinuous/prepare-features.d.ts +27 -0
- package/dist/discontinuous/prepare-features.d.ts.map +1 -1
- package/dist/discontinuous/prepare-features.js +106 -5
- package/dist/discontinuous/prepare-features.js.map +1 -1
- package/dist/discontinuous/rotated-map.d.ts +9 -0
- package/dist/discontinuous/rotated-map.d.ts.map +1 -1
- package/dist/discontinuous/source-arc.d.ts +4 -0
- package/dist/discontinuous/source-arc.d.ts.map +1 -0
- package/dist/discontinuous/source-arc.js +23 -0
- package/dist/discontinuous/source-arc.js.map +1 -0
- package/dist/discontinuous/world-kernels.d.ts +1 -1
- package/dist/discontinuous.cjs +1047 -75
- package/dist/discontinuous.cjs.map +3 -3
- package/dist/index.cjs +48 -0
- package/dist/index.cjs.map +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/turf.cjs +69 -5
- package/dist/turf.cjs.map +2 -2
- package/dist/turf.d.ts +9 -0
- package/dist/turf.d.ts.map +1 -1
- package/dist/turf.js +67 -0
- package/dist/turf.js.map +1 -1
- package/dist/workers/index.cjs +1075 -79
- package/dist/workers/index.cjs.map +3 -3
- package/dist/workers/operations.cjs +1049 -77
- package/dist/workers/operations.cjs.map +3 -3
- package/package.json +5 -5
- package/src/crs/crs-identifier.ts +86 -0
- package/src/crs/index.ts +1 -0
- package/src/discontinuous/cap-map.ts +248 -19
- package/src/discontinuous/elastic/geometry.ts +18 -7
- package/src/discontinuous/elastic/map.ts +334 -30
- package/src/discontinuous/elastic/source-arc.ts +129 -0
- package/src/discontinuous/global-polygons.ts +56 -2
- package/src/discontinuous/map-layout.ts +165 -2
- package/src/discontinuous/map-transition.ts +67 -3
- package/src/discontinuous/mercator-map.ts +151 -12
- package/src/discontinuous/polygon-constraints.ts +184 -0
- package/src/discontinuous/prepare-features.ts +154 -6
- package/src/discontinuous/source-arc.ts +31 -0
- package/src/index.ts +1 -0
- package/src/turf.ts +86 -0
|
@@ -48,18 +48,45 @@ export type PreparedMapGeometry = {
|
|
|
48
48
|
regionIds: string[];
|
|
49
49
|
/** One vertex per part. Point ownership follows MapEngine.projectPoint(). */
|
|
50
50
|
points: PreparedMapVertices & {parts: PreparedMapPart[]};
|
|
51
|
-
paths: PreparedMapVertices & {
|
|
51
|
+
paths: PreparedMapVertices & {
|
|
52
|
+
parts: PreparedMapPathPart[];
|
|
53
|
+
pathStarts: Uint32Array;
|
|
54
|
+
provenance?: {
|
|
55
|
+
sourceSegmentIndices?: Uint32Array;
|
|
56
|
+
sourceSegmentParameters?: Float64Array;
|
|
57
|
+
sourceVertexIndices?: Uint32Array;
|
|
58
|
+
sourceDistances?: Float64Array;
|
|
59
|
+
distanceRadius?: number;
|
|
60
|
+
/** Per part: source endpoint, coverage boundary, cut, or continuous join. */
|
|
61
|
+
startReasons?: string[];
|
|
62
|
+
endReasons?: string[];
|
|
63
|
+
};
|
|
64
|
+
};
|
|
52
65
|
polygons: PreparedMapVertices & {
|
|
53
66
|
parts: PreparedMapPart[];
|
|
54
67
|
/** Vertex offsets for all rings, with a terminal sentinel. Rings repeat their first vertex. */
|
|
55
68
|
ringStarts: Uint32Array;
|
|
56
69
|
/** Ring offsets for polygon parts, with a terminal sentinel. Outer ring comes first. */
|
|
57
70
|
polygonStarts: Uint32Array;
|
|
71
|
+
/** One edge from each vertex to the next; repeated closing vertices have kind 0. */
|
|
72
|
+
edgeProvenance?: {
|
|
73
|
+
kinds: Uint8Array;
|
|
74
|
+
sourceRingIndices: Uint32Array;
|
|
75
|
+
sourceSegmentIndices: Uint32Array;
|
|
76
|
+
sourceParameterRanges: Float64Array;
|
|
77
|
+
};
|
|
58
78
|
};
|
|
59
79
|
};
|
|
60
80
|
/** Static preparation controls. This does not triangulate, interpolate attributes or pose meshes. */
|
|
61
81
|
export type MapPrepareFeaturesOptions = {
|
|
62
82
|
sampling?: MapSamplingOptions;
|
|
83
|
+
provenance?: {
|
|
84
|
+
sourceSegments?: boolean;
|
|
85
|
+
boundaries?: boolean;
|
|
86
|
+
polygonEdges?: boolean;
|
|
87
|
+
/** Source minor-great-circle distance in meters on the declared sphere. */
|
|
88
|
+
distances?: {metric: 'spherical'; radius: number};
|
|
89
|
+
};
|
|
63
90
|
/** Project original polygon boundaries separately; default true. */
|
|
64
91
|
polygonOutlines?: boolean;
|
|
65
92
|
/** Directed global spherical polygons; original outlines never include atlas connectors. */
|
|
@@ -108,6 +135,45 @@ export function prepareMapFeatures(
|
|
|
108
135
|
if (!Array.isArray(features)) throw new Error('Expected a feature array');
|
|
109
136
|
if (options.polygonOutlines !== undefined && typeof options.polygonOutlines !== 'boolean')
|
|
110
137
|
throw new Error('polygonOutlines must be boolean');
|
|
138
|
+
const provenance = options.provenance;
|
|
139
|
+
if (
|
|
140
|
+
provenance !== undefined &&
|
|
141
|
+
(!provenance || typeof provenance !== 'object' || Array.isArray(provenance))
|
|
142
|
+
)
|
|
143
|
+
throw new Error('Unsupported provenance policy');
|
|
144
|
+
if (
|
|
145
|
+
provenance?.distances !== undefined &&
|
|
146
|
+
(!provenance.distances || typeof provenance.distances !== 'object')
|
|
147
|
+
)
|
|
148
|
+
throw new Error('Unsupported provenance distance policy');
|
|
149
|
+
if (
|
|
150
|
+
provenance &&
|
|
151
|
+
(typeof provenance !== 'object' ||
|
|
152
|
+
Object.keys(provenance).some(
|
|
153
|
+
k => !['sourceSegments', 'boundaries', 'distances', 'polygonEdges'].includes(k)
|
|
154
|
+
) ||
|
|
155
|
+
[provenance.sourceSegments, provenance.boundaries, provenance.polygonEdges].some(
|
|
156
|
+
v => v !== undefined && typeof v !== 'boolean'
|
|
157
|
+
) ||
|
|
158
|
+
(provenance.distances &&
|
|
159
|
+
(provenance.distances.metric !== 'spherical' ||
|
|
160
|
+
!Number.isFinite(provenance.distances.radius) ||
|
|
161
|
+
provenance.distances.radius <= 0)))
|
|
162
|
+
)
|
|
163
|
+
throw new Error('Unsupported provenance policy');
|
|
164
|
+
const edgeKinds: number[] = [],
|
|
165
|
+
edgeRings: number[] = [],
|
|
166
|
+
edgeSegments: number[] = [],
|
|
167
|
+
edgeParameters: number[] = [];
|
|
168
|
+
const lineage = Boolean(
|
|
169
|
+
provenance?.sourceSegments || provenance?.boundaries || provenance?.distances
|
|
170
|
+
);
|
|
171
|
+
const segments: number[] = [],
|
|
172
|
+
parameters: number[] = [],
|
|
173
|
+
originalVertices: number[] = [],
|
|
174
|
+
distances: number[] = [],
|
|
175
|
+
startReasons: string[] = [],
|
|
176
|
+
endReasons: string[] = [];
|
|
111
177
|
const regionIds = map.regions.map(r => r.id),
|
|
112
178
|
regionIndices = new Map(regionIds.map((id, i) => [id, i]));
|
|
113
179
|
const points = vertices(),
|
|
@@ -140,7 +206,28 @@ export function prepareMapFeatures(
|
|
|
140
206
|
if (line.length < 2) throw new Error('A line needs at least two positions');
|
|
141
207
|
const isRing = ringIndex !== undefined;
|
|
142
208
|
if (isRing && !closed(line)) line.push([...line[0]]);
|
|
143
|
-
for (const p of map.projectLine(line,
|
|
209
|
+
for (const p of map.projectLine(line, {
|
|
210
|
+
...options.sampling,
|
|
211
|
+
pathProvenance: lineage,
|
|
212
|
+
pathDistances: Boolean(provenance?.distances),
|
|
213
|
+
pathBoundaries: Boolean(provenance?.boundaries)
|
|
214
|
+
})) {
|
|
215
|
+
if (lineage) {
|
|
216
|
+
if (!p.provenance) throw new Error('Map backend does not support path provenance');
|
|
217
|
+
if (provenance?.sourceSegments) {
|
|
218
|
+
segments.push(...p.provenance.segments);
|
|
219
|
+
parameters.push(...p.provenance.parameters);
|
|
220
|
+
originalVertices.push(...p.provenance.vertices);
|
|
221
|
+
}
|
|
222
|
+
if (provenance?.distances)
|
|
223
|
+
distances.push(
|
|
224
|
+
...p.provenance.angularDistances.map(d => d * provenance.distances!.radius)
|
|
225
|
+
);
|
|
226
|
+
if (provenance?.boundaries) {
|
|
227
|
+
startReasons.push(p.provenance.startReason!);
|
|
228
|
+
endReasons.push(p.provenance.endReason!);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
144
231
|
append(paths, p.coordinates, p.sourceCoordinates);
|
|
145
232
|
pathParts.push({
|
|
146
233
|
...part(featureIndex, geometryPath, p.regionId),
|
|
@@ -159,10 +246,37 @@ export function prepareMapFeatures(
|
|
|
159
246
|
if (!input.length) return;
|
|
160
247
|
const rings = input.map(r => r.map(position));
|
|
161
248
|
const parts = options.sphericalCuts
|
|
162
|
-
? map.projectGlobalPolygon(rings, {
|
|
163
|
-
|
|
249
|
+
? map.projectGlobalPolygon(rings, {
|
|
250
|
+
...options.sampling,
|
|
251
|
+
...options.sphericalCuts,
|
|
252
|
+
polygonEdgeProvenance: provenance?.polygonEdges
|
|
253
|
+
})
|
|
254
|
+
: map.projectPolygon(rings, {
|
|
255
|
+
...options.sampling,
|
|
256
|
+
polygonEdgeProvenance: provenance?.polygonEdges
|
|
257
|
+
});
|
|
164
258
|
for (const p of parts) {
|
|
165
259
|
for (let i = 0; i < p.coordinates.length; i++) {
|
|
260
|
+
if (provenance?.polygonEdges) {
|
|
261
|
+
const edges = p.edgeProvenance?.[i];
|
|
262
|
+
if (!edges) throw new Error('Map backend does not support polygon edge provenance');
|
|
263
|
+
const kinds = [
|
|
264
|
+
'source-boundary',
|
|
265
|
+
'coverage-boundary',
|
|
266
|
+
'chart-cut',
|
|
267
|
+
'continuous-chart-join'
|
|
268
|
+
];
|
|
269
|
+
for (const edge of edges) {
|
|
270
|
+
edgeKinds.push(kinds.indexOf(edge.kind) + 1);
|
|
271
|
+
edgeRings.push(edge.ring);
|
|
272
|
+
edgeSegments.push(edge.segment);
|
|
273
|
+
edgeParameters.push(edge.t0, edge.t1);
|
|
274
|
+
}
|
|
275
|
+
edgeKinds.push(0);
|
|
276
|
+
edgeRings.push(0xffffffff);
|
|
277
|
+
edgeSegments.push(0xffffffff);
|
|
278
|
+
edgeParameters.push(0, 0);
|
|
279
|
+
}
|
|
166
280
|
append(polygons, p.coordinates[i], p.sourceCoordinates[i]);
|
|
167
281
|
ringStarts.push(polygons.positions.length / 2);
|
|
168
282
|
}
|
|
@@ -234,12 +348,46 @@ export function prepareMapFeatures(
|
|
|
234
348
|
featureIds,
|
|
235
349
|
regionIds,
|
|
236
350
|
points: {...pack(points), parts: pointParts},
|
|
237
|
-
paths: {
|
|
351
|
+
paths: {
|
|
352
|
+
...pack(paths),
|
|
353
|
+
parts: pathParts,
|
|
354
|
+
pathStarts: new Uint32Array(pathStarts),
|
|
355
|
+
...(lineage
|
|
356
|
+
? {
|
|
357
|
+
provenance: {
|
|
358
|
+
...(provenance?.sourceSegments
|
|
359
|
+
? {
|
|
360
|
+
sourceSegmentIndices: new Uint32Array(segments),
|
|
361
|
+
sourceSegmentParameters: new Float64Array(parameters),
|
|
362
|
+
sourceVertexIndices: new Uint32Array(originalVertices)
|
|
363
|
+
}
|
|
364
|
+
: {}),
|
|
365
|
+
...(provenance?.distances
|
|
366
|
+
? {
|
|
367
|
+
sourceDistances: new Float64Array(distances),
|
|
368
|
+
distanceRadius: provenance.distances.radius
|
|
369
|
+
}
|
|
370
|
+
: {}),
|
|
371
|
+
...(provenance?.boundaries ? {startReasons, endReasons} : {})
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
: {})
|
|
375
|
+
},
|
|
238
376
|
polygons: {
|
|
239
377
|
...pack(polygons),
|
|
240
378
|
parts: polygonParts,
|
|
241
379
|
ringStarts: new Uint32Array(ringStarts),
|
|
242
|
-
polygonStarts: new Uint32Array(polygonStarts)
|
|
380
|
+
polygonStarts: new Uint32Array(polygonStarts),
|
|
381
|
+
...(provenance?.polygonEdges
|
|
382
|
+
? {
|
|
383
|
+
edgeProvenance: {
|
|
384
|
+
kinds: new Uint8Array(edgeKinds),
|
|
385
|
+
sourceRingIndices: new Uint32Array(edgeRings),
|
|
386
|
+
sourceSegmentIndices: new Uint32Array(edgeSegments),
|
|
387
|
+
sourceParameterRanges: new Float64Array(edgeParameters)
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
: {})
|
|
243
391
|
}
|
|
244
392
|
};
|
|
245
393
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// math.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
|
|
4
|
+
import {angle, coordinates, geographic, unit, type Position, type Vector} from './math';
|
|
5
|
+
|
|
6
|
+
/** Preserve the source minor arc, including each owning chart's longitude side. */
|
|
7
|
+
export function sourceArc(a: Position, b: Position) {
|
|
8
|
+
const va = geographic(a),
|
|
9
|
+
vb = geographic(b),
|
|
10
|
+
length = angle(va, vb);
|
|
11
|
+
const poleA = Math.abs(a[1]) === 90,
|
|
12
|
+
poleB = Math.abs(b[1]) === 90;
|
|
13
|
+
const start: Position = poleA && !poleB ? [b[0], a[1]] : [...a],
|
|
14
|
+
end: Position = poleB && !poleA ? [a[0], b[1]] : [...b];
|
|
15
|
+
return (t: number): Position => {
|
|
16
|
+
if (t === 0) return [...start];
|
|
17
|
+
if (t === 1) return [...end];
|
|
18
|
+
if (length < 1e-14) return [a[0] + t * (b[0] - a[0]), a[1] + t * (b[1] - a[1])];
|
|
19
|
+
const p = coordinates(
|
|
20
|
+
unit(
|
|
21
|
+
va.map(
|
|
22
|
+
(v, k) =>
|
|
23
|
+
(Math.sin((1 - t) * length) * v + Math.sin(t * length) * vb[k]) / Math.sin(length)
|
|
24
|
+
) as Vector
|
|
25
|
+
)
|
|
26
|
+
);
|
|
27
|
+
const reference = start[0] + t * (end[0] - start[0]);
|
|
28
|
+
p[0] += 360 * Math.round((reference - p[0]) / 360);
|
|
29
|
+
return p;
|
|
30
|
+
};
|
|
31
|
+
}
|
package/src/index.ts
CHANGED
package/src/turf.ts
CHANGED
|
@@ -1198,3 +1198,89 @@ export function kinks(column: GeoArrowColumn): GeoArrowColumn {
|
|
|
1198
1198
|
return true;
|
|
1199
1199
|
});
|
|
1200
1200
|
}
|
|
1201
|
+
/** Arithmetic vertex mean per geometry, including polygon closing vertices (Turf centerMean semantics). */
|
|
1202
|
+
export function centerMean(column: GeoArrowColumn): GeoArrowColumn {
|
|
1203
|
+
const input = rows(column, native);
|
|
1204
|
+
return pointOutput(column, input.length, i => {
|
|
1205
|
+
const row = input[i];
|
|
1206
|
+
if (!row.valid) return null;
|
|
1207
|
+
let x = 0,
|
|
1208
|
+
y = 0,
|
|
1209
|
+
count = 0;
|
|
1210
|
+
walk(row.array, row.index, depths[column.encoding], p => {
|
|
1211
|
+
x += p[0];
|
|
1212
|
+
y += p[1];
|
|
1213
|
+
count++;
|
|
1214
|
+
});
|
|
1215
|
+
return count ? [x / count, y / count] : null;
|
|
1216
|
+
});
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
/** Clockwise angle at the middle point, with single-row broadcasting on all three inputs. */
|
|
1220
|
+
export function angle(
|
|
1221
|
+
start: GeoArrowColumn,
|
|
1222
|
+
middle: GeoArrowColumn,
|
|
1223
|
+
end: GeoArrowColumn,
|
|
1224
|
+
options: {mercator?: boolean; explementary?: boolean} = {}
|
|
1225
|
+
): TurfBatchResult<Float64Array> {
|
|
1226
|
+
const inputs = [start, middle, end].map(c => rows(c, points));
|
|
1227
|
+
const sizes = inputs.map(r => r.length),
|
|
1228
|
+
count = sizes.find(n => n !== 1) ?? 1;
|
|
1229
|
+
if (sizes.some(n => n !== 1 && n !== count))
|
|
1230
|
+
throw new RangeError('Angle batch lengths must match or contain one row');
|
|
1231
|
+
const out = result(count) as TurfBatchResult<Float64Array>;
|
|
1232
|
+
for (let i = 0; i < count; i++) {
|
|
1233
|
+
const p = inputs.map(r => {
|
|
1234
|
+
const row = r[r.length === 1 ? 0 : i];
|
|
1235
|
+
return row.valid ? point(row.array, row.index) : null;
|
|
1236
|
+
});
|
|
1237
|
+
if (p.some(v => !v)) continue;
|
|
1238
|
+
const heading = (a: Point, b: Point) =>
|
|
1239
|
+
options.mercator
|
|
1240
|
+
? rhumbAngle(a, b) / RAD
|
|
1241
|
+
: Math.atan2(
|
|
1242
|
+
Math.sin((b[0] - a[0]) * RAD) * Math.cos(b[1] * RAD),
|
|
1243
|
+
Math.cos(a[1] * RAD) * Math.sin(b[1] * RAD) -
|
|
1244
|
+
Math.sin(a[1] * RAD) * Math.cos(b[1] * RAD) * Math.cos((b[0] - a[0]) * RAD)
|
|
1245
|
+
) / RAD;
|
|
1246
|
+
const value = (heading(p[1], p[2]) - heading(p[1], p[0]) + 360) % 360;
|
|
1247
|
+
out.values[i] = options.explementary ? 360 - value : value;
|
|
1248
|
+
valid(out.validity, i);
|
|
1249
|
+
}
|
|
1250
|
+
return out;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
/** Tests corresponding LineString segments for parallel rhumb headings. */
|
|
1254
|
+
export function booleanParallel(a: GeoArrowColumn, b: GeoArrowColumn): TurfBatchResult<Uint8Array> {
|
|
1255
|
+
const left = rows(a, ['geoarrow.linestring']),
|
|
1256
|
+
right = rows(b, ['geoarrow.linestring']),
|
|
1257
|
+
count = paired(left, right),
|
|
1258
|
+
out = result(count, true) as TurfBatchResult<Uint8Array>;
|
|
1259
|
+
for (let i = 0; i < count; i++) {
|
|
1260
|
+
const x = left[left.length === 1 ? 0 : i],
|
|
1261
|
+
y = right[right.length === 1 ? 0 : i];
|
|
1262
|
+
if (!x.valid || !y.valid) continue;
|
|
1263
|
+
const p = segments(x, a.encoding),
|
|
1264
|
+
q = segments(y, b.encoding);
|
|
1265
|
+
let parallel = p.length > 0 && p.length === q.length;
|
|
1266
|
+
for (let j = 0; parallel && j < p.length; j++) {
|
|
1267
|
+
const u = point(p[j].array, p[j].index),
|
|
1268
|
+
v = point(p[j].array, p[j].index + 1),
|
|
1269
|
+
w = point(q[j].array, q[j].index),
|
|
1270
|
+
z = point(q[j].array, q[j].index + 1);
|
|
1271
|
+
if (!u || !v || !w || !z) {
|
|
1272
|
+
parallel = false;
|
|
1273
|
+
break;
|
|
1274
|
+
}
|
|
1275
|
+
const difference = (rhumbAngle(u, v) - rhumbAngle(w, z)) / RAD;
|
|
1276
|
+
const deviation = Math.abs(difference - Math.round(difference / 180) * 180);
|
|
1277
|
+
if (deviation > 1e-10) {
|
|
1278
|
+
parallel = false;
|
|
1279
|
+
break;
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
out.values[i] = Number(parallel);
|
|
1283
|
+
valid(out.validity, i);
|
|
1284
|
+
}
|
|
1285
|
+
return out;
|
|
1286
|
+
}
|