@lumikmz/kmz 0.11.1 → 0.11.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/index.mjs +2 -1
- package/package.json +1 -1
- package/src/plan/geometry.test.ts +49 -0
- package/src/plan/geometry.ts +6 -2
package/dist/index.mjs
CHANGED
|
@@ -366,7 +366,7 @@ function stabilizeTurnCorridors(segments) {
|
|
|
366
366
|
* (entry climb is a missionConfig behaviour, not a grid concern).
|
|
367
367
|
*/
|
|
368
368
|
function surveyGrid(ring, opts) {
|
|
369
|
-
const { directionDeg, marginM, lineSpacing,
|
|
369
|
+
const { directionDeg, marginM, lineSpacing, lengthwiseShiftM = 0 } = opts;
|
|
370
370
|
const t = directionDeg * DEG2RAD$1;
|
|
371
371
|
const rawAlpha = Math.atan2(Math.cos(t), Math.sin(t));
|
|
372
372
|
const alpha = Math.abs(rawAlpha) < ANGLE_EPS_RAD ? 0 : rawAlpha;
|
|
@@ -377,6 +377,7 @@ function surveyGrid(ring, opts) {
|
|
|
377
377
|
if (y < minY) minY = y;
|
|
378
378
|
if (y > maxY) maxY = y;
|
|
379
379
|
}
|
|
380
|
+
const phaseOffsetM = opts.phaseOffsetM ?? (maxY - minY <= lineSpacing ? (maxY - minY) / 2 : 0);
|
|
380
381
|
const scanSegments = [];
|
|
381
382
|
let leftToRight = true;
|
|
382
383
|
for (let y = minY + phaseOffsetM; y <= maxY + lineSpacing * .5; y += lineSpacing) {
|
package/package.json
CHANGED
|
@@ -71,6 +71,55 @@ describe("rotateEnu", () => {
|
|
|
71
71
|
});
|
|
72
72
|
|
|
73
73
|
describe("surveyGrid", () => {
|
|
74
|
+
it.each([
|
|
75
|
+
{ directionDeg: 90, lineSpacing: 100, start: [-100, 0], end: [100, 0] },
|
|
76
|
+
{ directionDeg: 90, lineSpacing: 200, start: [-100, 0], end: [100, 0] },
|
|
77
|
+
{ directionDeg: 0, lineSpacing: 200, start: [0, -50], end: [0, 50] },
|
|
78
|
+
{ directionDeg: 0, lineSpacing: 400, start: [0, -50], end: [0, 50] },
|
|
79
|
+
{ directionDeg: 270, lineSpacing: 200, start: [100, 0], end: [-100, 0] },
|
|
80
|
+
])(
|
|
81
|
+
"centers a narrow area's flight line at heading $directionDeg with spacing $lineSpacing",
|
|
82
|
+
({ directionDeg, lineSpacing, start, end }) => {
|
|
83
|
+
const diamond: EnuPoint[] = [
|
|
84
|
+
[0, -50],
|
|
85
|
+
[100, 0],
|
|
86
|
+
[0, 50],
|
|
87
|
+
[-100, 0],
|
|
88
|
+
];
|
|
89
|
+
const pts = surveyGrid(diamond, { directionDeg, marginM: 0, lineSpacing });
|
|
90
|
+
|
|
91
|
+
expect(pts).toHaveLength(2);
|
|
92
|
+
expect(pts[0]![0]).toBeCloseTo(start[0]!, 6);
|
|
93
|
+
expect(pts[0]![1]).toBeCloseTo(start[1]!, 6);
|
|
94
|
+
expect(pts[1]![0]).toBeCloseTo(end[0]!, 6);
|
|
95
|
+
expect(pts[1]![1]).toBeCloseTo(end[1]!, 6);
|
|
96
|
+
},
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
it.each([
|
|
100
|
+
{ phaseOffsetM: 0, expected: [] },
|
|
101
|
+
{
|
|
102
|
+
phaseOffsetM: 25,
|
|
103
|
+
expected: [
|
|
104
|
+
[-50, -25],
|
|
105
|
+
[50, -25],
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
])(
|
|
109
|
+
"preserves an explicit phase offset of $phaseOffsetM in a narrow area",
|
|
110
|
+
({ phaseOffsetM, expected }) => {
|
|
111
|
+
const diamond: EnuPoint[] = [
|
|
112
|
+
[0, -50],
|
|
113
|
+
[100, 0],
|
|
114
|
+
[0, 50],
|
|
115
|
+
[-100, 0],
|
|
116
|
+
];
|
|
117
|
+
expect(
|
|
118
|
+
surveyGrid(diamond, { directionDeg: 90, marginM: 0, lineSpacing: 200, phaseOffsetM }),
|
|
119
|
+
).toEqual(expected);
|
|
120
|
+
},
|
|
121
|
+
);
|
|
122
|
+
|
|
74
123
|
it("scans a square and returns paired flight-line endpoints", () => {
|
|
75
124
|
const pts = surveyGrid(SQUARE, { directionDeg: 90, marginM: 0, lineSpacing: 25 });
|
|
76
125
|
expect(pts.length).toBeGreaterThanOrEqual(8); // ≥4 lines × 2 endpoints
|
package/src/plan/geometry.ts
CHANGED
|
@@ -198,7 +198,8 @@ export interface SurveyGridOptions {
|
|
|
198
198
|
/**
|
|
199
199
|
* Across-track phase shift (meters) applied to every flight line.
|
|
200
200
|
* Used to interleave two grids on the same axis by half a line spacing
|
|
201
|
-
* (e.g. mapping3d forward vs backward oblique passes).
|
|
201
|
+
* (e.g. mapping3d forward vs backward oblique passes). Defaults to 0,
|
|
202
|
+
* or a centered line when the area is no wider than one line spacing.
|
|
202
203
|
*/
|
|
203
204
|
phaseOffsetM?: number;
|
|
204
205
|
/**
|
|
@@ -263,7 +264,7 @@ function stabilizeTurnCorridors(segments: ScanSegment[]): EnuPoint[] {
|
|
|
263
264
|
* (entry climb is a missionConfig behaviour, not a grid concern).
|
|
264
265
|
*/
|
|
265
266
|
export function surveyGrid(ring: readonly EnuPoint[], opts: SurveyGridOptions): EnuPoint[] {
|
|
266
|
-
const { directionDeg, marginM, lineSpacing,
|
|
267
|
+
const { directionDeg, marginM, lineSpacing, lengthwiseShiftM = 0 } = opts;
|
|
267
268
|
// Map the heading clockwise-from-north → CCW angle from +x axis
|
|
268
269
|
const t = directionDeg * DEG2RAD;
|
|
269
270
|
const rawAlpha = Math.atan2(Math.cos(t), Math.sin(t));
|
|
@@ -277,6 +278,9 @@ export function surveyGrid(ring: readonly EnuPoint[], opts: SurveyGridOptions):
|
|
|
277
278
|
if (y > maxY) maxY = y;
|
|
278
279
|
}
|
|
279
280
|
|
|
281
|
+
// A boundary scan may only touch a vertex. Center a single line in narrow
|
|
282
|
+
// areas, while retaining explicit phases used by interleaved/strip grids.
|
|
283
|
+
const phaseOffsetM = opts.phaseOffsetM ?? (maxY - minY <= lineSpacing ? (maxY - minY) / 2 : 0);
|
|
280
284
|
const scanSegments: ScanSegment[] = [];
|
|
281
285
|
let leftToRight = true;
|
|
282
286
|
for (let y = minY + phaseOffsetM; y <= maxY + lineSpacing * 0.5; y += lineSpacing) {
|