@lumikmz/kmz 0.2.0 → 0.3.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/README.md +69 -66
- package/dist/index.d.mts +215 -76
- package/dist/index.mjs +634 -157
- package/package.json +1 -1
- package/src/index.ts +2 -1
- package/src/plan/geometry.test.ts +96 -0
- package/src/plan/geometry.ts +161 -25
- package/src/plan/index.ts +23 -3
- package/src/plan/plan-mapping-strip.ts +3 -3
- package/src/plan/plan-mapping2d.ts +512 -89
- package/src/plan/plan-mapping3d.ts +157 -98
- package/src/plan/plan.test.ts +263 -9
- package/src/types/action.ts +65 -1
- package/src/types/drone-payload.ts +18 -12
- package/src/types/enums.ts +17 -3
- package/src/types/mission-config.ts +5 -0
- package/src/types/placemark.ts +92 -15
- package/src/types/template.ts +12 -76
- package/src/types/waylines.ts +12 -3
- package/src/types/waypoint-params.ts +18 -0
package/README.md
CHANGED
|
@@ -38,12 +38,12 @@ Compile a `Template` into the executable `Waylines` shape that DJI's flight cont
|
|
|
38
38
|
|
|
39
39
|
Dispatch is by `template.Folder.templateType`:
|
|
40
40
|
|
|
41
|
-
| templateType
|
|
42
|
-
|
|
|
43
|
-
| `waypoint`
|
|
44
|
-
| `mapping2d`
|
|
45
|
-
| `mapping3d`
|
|
46
|
-
| `mappingStrip`
|
|
41
|
+
| templateType | Algorithm |
|
|
42
|
+
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
43
|
+
| `waypoint` | One Folder. Each template Placemark → one wayline Placemark, resolving `useGlobalXxx` flags against folder defaults. |
|
|
44
|
+
| `mapping2d` | One Folder. Boustrophedon (serpentine) scan over the Polygon at `folder.height`, line spacing computed from `overlap.orthoCameraOverlapW`. Per-segment `takePhoto` between adjacent points. |
|
|
45
|
+
| `mapping3d` | **Five Folders** — one nadir ortho pass + four oblique passes (front/back/left/right) at `inclinedGimbalPitch`. Photos timed via `multipleTiming` trigger. |
|
|
46
|
+
| `mappingStrip` | One Folder. LineString vertices become waypoints; if `stripUseTemplateAltitude` is true, per-vertex altitude is read from the LineString triples, otherwise folder `height` is used. |
|
|
47
47
|
|
|
48
48
|
```ts
|
|
49
49
|
import { plan } from "@lumikmz/kmz";
|
|
@@ -74,7 +74,7 @@ Checks performed:
|
|
|
74
74
|
|
|
75
75
|
```ts
|
|
76
76
|
interface Issue {
|
|
77
|
-
path: string;
|
|
77
|
+
path: string; // dot-path to the offending field, e.g. "Folder.Placemark[2].waypointSpeed"
|
|
78
78
|
message: string;
|
|
79
79
|
severity: "error" | "warning";
|
|
80
80
|
}
|
|
@@ -85,16 +85,12 @@ interface Issue {
|
|
|
85
85
|
### Document roots: `Template` & `Waylines`
|
|
86
86
|
|
|
87
87
|
```ts
|
|
88
|
-
type Template =
|
|
89
|
-
| WaypointTemplate
|
|
90
|
-
| Mapping2dTemplate
|
|
91
|
-
| Mapping3dTemplate
|
|
92
|
-
| MappingStripTemplate;
|
|
88
|
+
type Template = WaypointTemplate | Mapping2dTemplate | Mapping3dTemplate | MappingStripTemplate;
|
|
93
89
|
|
|
94
90
|
interface TemplateDocumentBase {
|
|
95
91
|
author?: string;
|
|
96
|
-
createTime?: number;
|
|
97
|
-
updateTime?: number;
|
|
92
|
+
createTime?: number; // Unix ms
|
|
93
|
+
updateTime?: number; // Unix ms
|
|
98
94
|
missionConfig: MissionConfig;
|
|
99
95
|
// Folder is added per variant
|
|
100
96
|
}
|
|
@@ -123,15 +119,15 @@ interface MissionConfig {
|
|
|
123
119
|
flyToWaylineMode: "safely" | "pointToPoint";
|
|
124
120
|
finishAction: "goHome" | "noAction" | "autoLand" | "gotoFirstWaypoint";
|
|
125
121
|
exitOnRCLost: "goContinue" | "executeLostAction";
|
|
126
|
-
executeRCLostAction?: "goBack" | "landing" | "hover";
|
|
122
|
+
executeRCLostAction?: "goBack" | "landing" | "hover"; // required iff exitOnRCLost === "executeLostAction"
|
|
127
123
|
takeOffSecurityHeight: Meters;
|
|
128
124
|
takeOffRefPoint?: LngLatHeight;
|
|
129
125
|
takeOffRefPointAGLHeight?: Meters;
|
|
130
|
-
globalTransitionalSpeed: MetersPerSecond;
|
|
131
|
-
globalRTHHeight: Meters;
|
|
126
|
+
globalTransitionalSpeed: MetersPerSecond; // [1, 15]
|
|
127
|
+
globalRTHHeight: Meters; // [2, 1500]
|
|
132
128
|
droneInfo: DroneInfo;
|
|
133
129
|
payloadInfo: PayloadInfo[];
|
|
134
|
-
autoRerouteInfo?: AutoRerouteInfo;
|
|
130
|
+
autoRerouteInfo?: AutoRerouteInfo; // M3D/M3TD, M4D/M4TD, M4E/M4T only
|
|
135
131
|
}
|
|
136
132
|
|
|
137
133
|
interface DroneInfo {
|
|
@@ -165,9 +161,9 @@ interface WaypointFolder {
|
|
|
165
161
|
payloadParam?: PayloadParam;
|
|
166
162
|
|
|
167
163
|
globalWaypointTurnMode: WaypointTurnMode;
|
|
168
|
-
globalUseStraightLine?: boolean;
|
|
164
|
+
globalUseStraightLine?: boolean; // required iff turnMode ∈ {ContinuityCurvature variants}
|
|
169
165
|
gimbalPitchMode: "manual" | "usePointSetting";
|
|
170
|
-
globalHeight: Meters;
|
|
166
|
+
globalHeight: Meters; // relative to takeoff point
|
|
171
167
|
globalWaypointHeadingParam: WaypointHeadingParam;
|
|
172
168
|
|
|
173
169
|
Placemark: TemplateWaypointPlacemark[];
|
|
@@ -184,23 +180,23 @@ interface Mapping2dFolder {
|
|
|
184
180
|
autoFlightSpeed: MetersPerSecond;
|
|
185
181
|
payloadParam?: PayloadParam;
|
|
186
182
|
|
|
187
|
-
caliFlightEnable?: boolean;
|
|
183
|
+
caliFlightEnable?: boolean; // M300/M350 only
|
|
188
184
|
elevationOptimizeEnable: boolean;
|
|
189
|
-
smartObliqueEnable?: boolean;
|
|
185
|
+
smartObliqueEnable?: boolean; // turns "ortho" into "smart oblique"
|
|
190
186
|
smartObliqueGimbalPitch?: Degrees;
|
|
191
187
|
|
|
192
188
|
shootType: "time" | "distance";
|
|
193
|
-
direction: Degrees;
|
|
189
|
+
direction: Degrees; // [0, 360]
|
|
194
190
|
margin: number;
|
|
195
191
|
overlap: Overlap;
|
|
196
192
|
ellipsoidHeight: Meters;
|
|
197
193
|
height: Meters;
|
|
198
194
|
|
|
199
|
-
facadeWaylineEnable?: boolean;
|
|
195
|
+
facadeWaylineEnable?: boolean; // M3E/M3T/M3M only
|
|
200
196
|
mappingHeadingParam?: MappingHeadingParam;
|
|
201
197
|
gimbalPitchMode?: "manual" | "fixed";
|
|
202
|
-
gimbalPitchAngle?: Degrees;
|
|
203
|
-
quickOrthoMappingEnable?: boolean;
|
|
198
|
+
gimbalPitchAngle?: Degrees; // required iff gimbalPitchMode === "fixed"
|
|
199
|
+
quickOrthoMappingEnable?: boolean; // M4E only
|
|
204
200
|
quickOrthoMappingPitch?: Degrees;
|
|
205
201
|
|
|
206
202
|
Placemark: TemplatePolygonPlacemark;
|
|
@@ -218,8 +214,8 @@ interface Mapping3dFolder {
|
|
|
218
214
|
payloadParam?: PayloadParam;
|
|
219
215
|
|
|
220
216
|
caliFlightEnable?: boolean;
|
|
221
|
-
inclinedGimbalPitch: Degrees;
|
|
222
|
-
inclinedFlightSpeed: MetersPerSecond;
|
|
217
|
+
inclinedGimbalPitch: Degrees; // pitch for the 4 oblique passes
|
|
218
|
+
inclinedFlightSpeed: MetersPerSecond; // [1, 15]
|
|
223
219
|
shootType: "time" | "distance";
|
|
224
220
|
direction: Degrees;
|
|
225
221
|
margin: number;
|
|
@@ -244,7 +240,7 @@ interface MappingStripFolder {
|
|
|
244
240
|
caliFlightEnable: boolean;
|
|
245
241
|
shootType: "time" | "distance";
|
|
246
242
|
direction: Degrees;
|
|
247
|
-
margin: number;
|
|
243
|
+
margin: number; // float (vs integer in mapping2d/3d)
|
|
248
244
|
singleLineEnable: boolean;
|
|
249
245
|
cuttingDistance: number;
|
|
250
246
|
boundaryOptimEnable: boolean;
|
|
@@ -254,7 +250,7 @@ interface MappingStripFolder {
|
|
|
254
250
|
overlap: Overlap;
|
|
255
251
|
ellipsoidHeight: Meters;
|
|
256
252
|
height: Meters;
|
|
257
|
-
stripUseTemplateAltitude: boolean;
|
|
253
|
+
stripUseTemplateAltitude: boolean; // when true, alt is read from LineString triples
|
|
258
254
|
|
|
259
255
|
Placemark: TemplateLineStringPlacemark;
|
|
260
256
|
}
|
|
@@ -268,15 +264,15 @@ Two Placemark shapes — one for `template.kml`, one for `waylines.wpml`.
|
|
|
268
264
|
|
|
269
265
|
```ts
|
|
270
266
|
interface TemplateWaypointPlacemark {
|
|
271
|
-
Point: { coordinates: LngLat };
|
|
267
|
+
Point: { coordinates: LngLat }; // KML order: lng,lat
|
|
272
268
|
index: number;
|
|
273
269
|
|
|
274
270
|
useGlobalHeight: boolean;
|
|
275
|
-
ellipsoidHeight?: Meters;
|
|
276
|
-
height?: Meters;
|
|
271
|
+
ellipsoidHeight?: Meters; // required iff useGlobalHeight=false; WGS84
|
|
272
|
+
height?: Meters; // required iff useGlobalHeight=false
|
|
277
273
|
|
|
278
274
|
useGlobalSpeed: boolean;
|
|
279
|
-
waypointSpeed?: MetersPerSecond;
|
|
275
|
+
waypointSpeed?: MetersPerSecond; // required iff useGlobalSpeed=false; [1, 15]
|
|
280
276
|
|
|
281
277
|
useGlobalHeadingParam: boolean;
|
|
282
278
|
waypointHeadingParam?: WaypointHeadingParam;
|
|
@@ -284,9 +280,9 @@ interface TemplateWaypointPlacemark {
|
|
|
284
280
|
useGlobalTurnParam: boolean;
|
|
285
281
|
waypointTurnParam?: WaypointTurnParam;
|
|
286
282
|
|
|
287
|
-
useStraightLine?: boolean;
|
|
288
|
-
gimbalPitchAngle?: Degrees;
|
|
289
|
-
isRisky?: boolean;
|
|
283
|
+
useStraightLine?: boolean; // required for certain turn modes
|
|
284
|
+
gimbalPitchAngle?: Degrees; // required iff folder gimbalPitchMode === "usePointSetting"
|
|
285
|
+
isRisky?: boolean; // M30/M30T, M3D/M3TD, M4D/M4TD, M4E/M4T
|
|
290
286
|
|
|
291
287
|
actionGroup?: ActionGroup[];
|
|
292
288
|
}
|
|
@@ -300,7 +296,7 @@ interface TemplatePolygonPlacemark {
|
|
|
300
296
|
}
|
|
301
297
|
|
|
302
298
|
interface TemplateLineStringPlacemark {
|
|
303
|
-
LineString: { coordinates: string };
|
|
299
|
+
LineString: { coordinates: string }; // space-separated lng,lat,alt triples
|
|
304
300
|
}
|
|
305
301
|
```
|
|
306
302
|
|
|
@@ -312,8 +308,8 @@ The `useGlobalXxx` switches are template-only — in `waylines.wpml` all params
|
|
|
312
308
|
interface WaylinesPlacemark {
|
|
313
309
|
Point: { coordinates: LngLat };
|
|
314
310
|
index: number;
|
|
315
|
-
executeHeight: Meters;
|
|
316
|
-
waypointSpeed: MetersPerSecond;
|
|
311
|
+
executeHeight: Meters; // interpreted per Folder.executeHeightMode
|
|
312
|
+
waypointSpeed: MetersPerSecond; // [1, 15]
|
|
317
313
|
waypointHeadingParam: WaypointHeadingParam;
|
|
318
314
|
waypointTurnParam: WaypointTurnParam;
|
|
319
315
|
useStraightLine?: boolean;
|
|
@@ -327,9 +323,9 @@ interface WaylinesPlacemark {
|
|
|
327
323
|
```ts
|
|
328
324
|
interface WaypointHeadingParam {
|
|
329
325
|
waypointHeadingMode: "followWayline" | "manually" | "fixed" | "smoothTransition" | "towardPOI";
|
|
330
|
-
waypointHeadingAngle?: Degrees;
|
|
331
|
-
waypointPoiPoint?: LngLatHeight;
|
|
332
|
-
waypointHeadingPathMode: "clockwise" | "counterClockwise" | "followBadArc";
|
|
326
|
+
waypointHeadingAngle?: Degrees; // [-180, 180]; required iff mode === "smoothTransition"
|
|
327
|
+
waypointPoiPoint?: LngLatHeight; // required iff mode === "towardPOI"; height should be 0
|
|
328
|
+
waypointHeadingPathMode: "clockwise" | "counterClockwise" | "followBadArc"; // spec typo preserved
|
|
333
329
|
}
|
|
334
330
|
|
|
335
331
|
interface WaypointTurnParam {
|
|
@@ -338,27 +334,27 @@ interface WaypointTurnParam {
|
|
|
338
334
|
| "toPointAndStopWithDiscontinuityCurvature"
|
|
339
335
|
| "toPointAndStopWithContinuityCurvature"
|
|
340
336
|
| "toPointAndPassWithContinuityCurvature";
|
|
341
|
-
waypointTurnDampingDist?: Meters;
|
|
337
|
+
waypointTurnDampingDist?: Meters; // required for coordinateTurn or pass+useStraightLine
|
|
342
338
|
}
|
|
343
339
|
|
|
344
340
|
interface WaylineCoordinateSysParam {
|
|
345
|
-
coordinateMode: "WGS84";
|
|
341
|
+
coordinateMode: "WGS84"; // only value currently
|
|
346
342
|
heightMode: "EGM96" | "relativeToStartPoint" | "aboveGroundLevel" | "realTimeFollowSurface";
|
|
347
343
|
positioningType?: "GPS" | "RTKBaseStation" | "QianXun" | "Custom";
|
|
348
|
-
globalShootHeight?: Meters;
|
|
349
|
-
surfaceFollowModeEnable?: boolean;
|
|
350
|
-
surfaceRelativeHeight?: Meters;
|
|
344
|
+
globalShootHeight?: Meters; // mapping templates
|
|
345
|
+
surfaceFollowModeEnable?: boolean; // mapping templates
|
|
346
|
+
surfaceRelativeHeight?: Meters; // required iff surfaceFollowModeEnable === true
|
|
351
347
|
}
|
|
352
348
|
|
|
353
349
|
interface MappingHeadingParam {
|
|
354
350
|
mappingHeadingMode: "fixed" | "followWayline";
|
|
355
|
-
mappingHeadingAngle?: Degrees;
|
|
351
|
+
mappingHeadingAngle?: Degrees; // [0, 360]; required iff mode === "fixed"
|
|
356
352
|
}
|
|
357
353
|
|
|
358
354
|
interface Overlap {
|
|
359
|
-
orthoLidarOverlapH?: number;
|
|
355
|
+
orthoLidarOverlapH?: number; // 0–100, M300/M350 LiDAR
|
|
360
356
|
orthoLidarOverlapW?: number;
|
|
361
|
-
orthoCameraOverlapH?: number;
|
|
357
|
+
orthoCameraOverlapH?: number; // 0–100, visible light
|
|
362
358
|
orthoCameraOverlapW?: number;
|
|
363
359
|
inclinedLidarOverlapH?: number;
|
|
364
360
|
inclinedLidarOverlapW?: number;
|
|
@@ -375,15 +371,15 @@ interface Overlap {
|
|
|
375
371
|
interface ActionGroup {
|
|
376
372
|
actionGroupId: number;
|
|
377
373
|
actionGroupStartIndex: number;
|
|
378
|
-
actionGroupEndIndex: number;
|
|
379
|
-
actionGroupMode: "sequence";
|
|
374
|
+
actionGroupEndIndex: number; // ≥ start; equal means single-waypoint group
|
|
375
|
+
actionGroupMode: "sequence"; // only value currently
|
|
380
376
|
actionTrigger: ActionTrigger;
|
|
381
|
-
action: Action[];
|
|
377
|
+
action: Action[]; // 1..*
|
|
382
378
|
}
|
|
383
379
|
|
|
384
380
|
interface ActionTrigger {
|
|
385
381
|
actionTriggerType: "reachPoint" | "betweenAdjacentPoints" | "multipleTiming" | "multipleDistance";
|
|
386
|
-
actionTriggerParam?: number;
|
|
382
|
+
actionTriggerParam?: number; // seconds for multipleTiming; meters for multipleDistance
|
|
387
383
|
}
|
|
388
384
|
|
|
389
385
|
type Action =
|
|
@@ -411,7 +407,7 @@ Every `Action` has the shape:
|
|
|
411
407
|
interface ActionBase<F extends string, P> {
|
|
412
408
|
actionId: number;
|
|
413
409
|
actionActuatorFunc: F;
|
|
414
|
-
actionActuatorFuncParam: P;
|
|
410
|
+
actionActuatorFuncParam: P; // shape depends on F
|
|
415
411
|
}
|
|
416
412
|
```
|
|
417
413
|
|
|
@@ -421,7 +417,7 @@ The 16 param shapes match [`docs/kmz/common-element.html` §action](../../docs/k
|
|
|
421
417
|
interface TakePhotoParam {
|
|
422
418
|
payloadPositionIndex: number;
|
|
423
419
|
fileSuffix?: string;
|
|
424
|
-
payloadLensIndex?: LensType[];
|
|
420
|
+
payloadLensIndex?: LensType[]; // ["wide", "ir", ...]
|
|
425
421
|
useGlobalPayloadLensIndex: boolean;
|
|
426
422
|
}
|
|
427
423
|
|
|
@@ -436,11 +432,11 @@ interface GimbalRotateParam {
|
|
|
436
432
|
gimbalYawRotateEnable: boolean;
|
|
437
433
|
gimbalYawRotateAngle: Degrees;
|
|
438
434
|
gimbalRotateTimeEnable: boolean;
|
|
439
|
-
gimbalRotateTime: number;
|
|
435
|
+
gimbalRotateTime: number; // seconds
|
|
440
436
|
}
|
|
441
437
|
|
|
442
438
|
interface HoverParam {
|
|
443
|
-
hoverTime: number;
|
|
439
|
+
hoverTime: number; // seconds, > 0
|
|
444
440
|
}
|
|
445
441
|
```
|
|
446
442
|
|
|
@@ -451,18 +447,25 @@ For the full list — including `accurateShoot` (deprecated, prefer `orientedSho
|
|
|
451
447
|
Nominal types to prevent unit mix-ups. They are plain numbers at runtime.
|
|
452
448
|
|
|
453
449
|
```ts
|
|
454
|
-
type Meters
|
|
450
|
+
type Meters = number & { readonly __brand: "Meters" };
|
|
455
451
|
type MetersPerSecond = number & { readonly __brand: "MetersPerSecond" };
|
|
456
|
-
type Degrees
|
|
452
|
+
type Degrees = number & { readonly __brand: "Degrees" };
|
|
457
453
|
|
|
458
454
|
// Constructors (no-op at runtime)
|
|
459
|
-
const meters
|
|
455
|
+
const meters = (n: number): Meters => n as Meters;
|
|
460
456
|
const metersPerSecond = (n: number): MetersPerSecond => n as MetersPerSecond;
|
|
461
|
-
const degrees
|
|
457
|
+
const degrees = (n: number): Degrees => n as Degrees;
|
|
462
458
|
|
|
463
459
|
// Geographic types
|
|
464
|
-
interface LngLat
|
|
465
|
-
|
|
460
|
+
interface LngLat {
|
|
461
|
+
lng: number;
|
|
462
|
+
lat: number;
|
|
463
|
+
}
|
|
464
|
+
interface LngLatHeight {
|
|
465
|
+
lng: number;
|
|
466
|
+
lat: number;
|
|
467
|
+
height: Meters;
|
|
468
|
+
}
|
|
466
469
|
```
|
|
467
470
|
|
|
468
471
|
### Enums
|
|
@@ -533,7 +536,7 @@ Output is always a single `Waylines` object containing `1..n` `Folder` entries.
|
|
|
533
536
|
|
|
534
537
|
## Compatibility
|
|
535
538
|
|
|
536
|
-
[DJI WPML 1.
|
|
539
|
+
[DJI WPML 1.15](https://developer.dji.com/doc/cloud-api-tutorial/cn/api-reference/dji-wpml/overview.html) — see [`docs/kmz-types-spec.md`](../../docs/kmz-types-spec.md) for the distilled spec this package mirrors.
|
|
537
540
|
|
|
538
541
|
## License
|
|
539
542
|
|