@orbat-mapper/control-measures 0.2.0-alpha.6 → 0.2.0-alpha.7
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
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as point12DrawRule, A as DEFAULT_GENERIC_POLYGON_OPTIONS, B as DEFAULT_ANTITANK_WALL_OPTIONS, C as DEFAULT_FIX_OPTIONS, D as DEFAULT_DELAY_OPTIONS, E as DEFAULT_DISRUPT_OPTIONS, F as DEFAULT_BREACH_OPTIONS, G as axis1DrawRule, H as DEFAULT_AMBUSH_OPTIONS, I as DEFAULT_BLOCK_MISSION_TASK_OPTIONS, J as line23DrawRule, K as supportByFireDrawRule, L as DEFAULT_BLOCK_OPTIONS, M as DEFAULT_GENERIC_CIRCLE_OPTIONS, N as DEFAULT_CANALIZE_OPTIONS, O as DEFAULT_CLEAR_OPTIONS, P as DEFAULT_BYPASS_OPTIONS, Q as attackByFireDrawRule, R as DEFAULT_ATTACK_HELICOPTER_OPTIONS, S as DEFAULT_FLOT_OPTIONS, T as DEFAULT_ENCIRCLEMENT_OPTIONS, U as DEFAULT_AIRBORNE_ATTACK_OPTIONS, V as DEFAULT_ANTITANK_DITCH_OPTIONS, W as rectangleDrawRule, X as line1DrawRule, Y as turnDrawRule, Z as ambushDrawRule, _ as DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, a as DEFINITIONS, at as getMidpointPerpendicularSignedDistance, b as DEFAULT_FORTIFIED_AREA_OPTIONS, c as getDefaultOptions, ct as createBaselineFrame, d as DEFAULT_SUPPORTING_ATTACK_OPTIONS, dt as project, et as centerRadiusDrawRule, f as DEFAULT_SUPPORT_BY_FIRE_OPTIONS, ft as unproject, g as DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, h as DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, ht as roundToFixed, i as CONTROL_MEASURE_METADATA, it as createMidpointPerpendicularDrawRule, j as DEFAULT_GENERIC_LINE_OPTIONS, k as DEFAULT_GENERIC_RECTANGLE_OPTIONS, l as listControlMeasureMetadata, lt as calculateMetrics, m as DEFAULT_TACTICAL_ARROW_OPTIONS, mt as getMetersPerPixel, n as resolveStyleHints, nt as blockDrawRule, o as getControlMeasureMetadata, ot as pointOnMidpointPerpendicularAxis, p as DEFAULT_STRONG_POINT_OPTIONS, pt as EPSILON, q as line24DrawRule, r as CONTROL_MEASURE_IDS, rt as computeDefaultMidpointPerpendicularPoint, s as getControlMeasureMetadataByValue, st as snapToMidpointPerpendicular, t as renderControlMeasure, tt as disruptDrawRule, u as DEFAULT_TURN_OPTIONS, ut as computeInitialWidthPoint, v as DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, w as DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, x as DEFAULT_FORTIFIED_LINE_OPTIONS, y as DEFAULT_MAIN_ATTACK_OPTIONS, z as DEFAULT_ATTACK_BY_FIRE_OPTIONS } from "./renderControlMeasure-
|
|
1
|
+
import { $ as point12DrawRule, A as DEFAULT_GENERIC_POLYGON_OPTIONS, B as DEFAULT_ANTITANK_WALL_OPTIONS, C as DEFAULT_FIX_OPTIONS, D as DEFAULT_DELAY_OPTIONS, E as DEFAULT_DISRUPT_OPTIONS, F as DEFAULT_BREACH_OPTIONS, G as axis1DrawRule, H as DEFAULT_AMBUSH_OPTIONS, I as DEFAULT_BLOCK_MISSION_TASK_OPTIONS, J as line23DrawRule, K as supportByFireDrawRule, L as DEFAULT_BLOCK_OPTIONS, M as DEFAULT_GENERIC_CIRCLE_OPTIONS, N as DEFAULT_CANALIZE_OPTIONS, O as DEFAULT_CLEAR_OPTIONS, P as DEFAULT_BYPASS_OPTIONS, Q as attackByFireDrawRule, R as DEFAULT_ATTACK_HELICOPTER_OPTIONS, S as DEFAULT_FLOT_OPTIONS, T as DEFAULT_ENCIRCLEMENT_OPTIONS, U as DEFAULT_AIRBORNE_ATTACK_OPTIONS, V as DEFAULT_ANTITANK_DITCH_OPTIONS, W as rectangleDrawRule, X as line1DrawRule, Y as turnDrawRule, Z as ambushDrawRule, _ as DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, a as DEFINITIONS, at as getMidpointPerpendicularSignedDistance, b as DEFAULT_FORTIFIED_AREA_OPTIONS, c as getDefaultOptions, ct as createBaselineFrame, d as DEFAULT_SUPPORTING_ATTACK_OPTIONS, dt as project, et as centerRadiusDrawRule, f as DEFAULT_SUPPORT_BY_FIRE_OPTIONS, ft as unproject, g as DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, h as DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, ht as roundToFixed, i as CONTROL_MEASURE_METADATA, it as createMidpointPerpendicularDrawRule, j as DEFAULT_GENERIC_LINE_OPTIONS, k as DEFAULT_GENERIC_RECTANGLE_OPTIONS, l as listControlMeasureMetadata, lt as calculateMetrics, m as DEFAULT_TACTICAL_ARROW_OPTIONS, mt as getMetersPerPixel, n as resolveStyleHints, nt as blockDrawRule, o as getControlMeasureMetadata, ot as pointOnMidpointPerpendicularAxis, p as DEFAULT_STRONG_POINT_OPTIONS, pt as EPSILON, q as line24DrawRule, r as CONTROL_MEASURE_IDS, rt as computeDefaultMidpointPerpendicularPoint, s as getControlMeasureMetadataByValue, st as snapToMidpointPerpendicular, t as renderControlMeasure, tt as disruptDrawRule, u as DEFAULT_TURN_OPTIONS, ut as computeInitialWidthPoint, v as DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, w as DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, x as DEFAULT_FORTIFIED_LINE_OPTIONS, y as DEFAULT_MAIN_ATTACK_OPTIONS, z as DEFAULT_ATTACK_BY_FIRE_OPTIONS } from "./renderControlMeasure-DGWf44sn.mjs";
|
|
2
2
|
//#region src/freeze-orientation.ts
|
|
3
3
|
/**
|
|
4
4
|
* Dispatches to a measure kind's `freezeOrientation` hook (see
|
package/dist/preview/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as DEFINITIONS, t as renderControlMeasure } from "../renderControlMeasure-
|
|
1
|
+
import { a as DEFINITIONS, t as renderControlMeasure } from "../renderControlMeasure-DGWf44sn.mjs";
|
|
2
2
|
//#region src/preview/index.ts
|
|
3
3
|
/**
|
|
4
4
|
* Unitless `previewSample` points (~`[-1, 1]`) are scaled by this degree offset
|
|
@@ -181,7 +181,7 @@ function pointToInfiniteLineDistance(p, a, b) {
|
|
|
181
181
|
}
|
|
182
182
|
/**
|
|
183
183
|
* Calculates intersection of two line segments p1-p2 and p3-p4.
|
|
184
|
-
* Returns null if parallel
|
|
184
|
+
* Returns null if parallel or if the infinite lines intersect outside either segment.
|
|
185
185
|
*/
|
|
186
186
|
function lineIntersection(p1, p2, p3, p4) {
|
|
187
187
|
const x1 = p1[0], y1 = p1[1];
|
|
@@ -191,6 +191,8 @@ function lineIntersection(p1, p2, p3, p4) {
|
|
|
191
191
|
const denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
|
|
192
192
|
if (Math.abs(denom) < 1e-6) return null;
|
|
193
193
|
const ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denom;
|
|
194
|
+
const ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denom;
|
|
195
|
+
if (ua < -1e-6 || ua > 1.000001 || ub < -1e-6 || ub > 1.000001) return null;
|
|
194
196
|
return [x1 + ua * (x2 - x1), y1 + ua * (y2 - y1)];
|
|
195
197
|
}
|
|
196
198
|
//#endregion
|
|
@@ -218,15 +220,38 @@ function processAttackGeometry(coordinates, options = {}) {
|
|
|
218
220
|
return { geometry: calculateSymbolGeometry(ptTip, ptWidth, spinePoints, shaftRatio, roundedBends, bendSegments) };
|
|
219
221
|
}
|
|
220
222
|
function calculateSymbolGeometry(ptTip, ptWidth, spine, shaftRatio, roundedBends, bendSegments) {
|
|
221
|
-
const
|
|
223
|
+
const initialNeck = spine[spine.length - 1];
|
|
224
|
+
if (!initialNeck) return null;
|
|
225
|
+
const initialTipDir = vecNorm(vecSub(ptTip, initialNeck));
|
|
226
|
+
if (vecMag(initialTipDir) < 1e-6) return null;
|
|
227
|
+
const headHalfWidth = pointToInfiniteLineDistance(ptWidth, initialNeck, ptTip);
|
|
228
|
+
const vecTipToWidth = vecSub(ptTip, ptWidth);
|
|
229
|
+
const requestedHeadLength = Math.max(EPSILON, vecDot(vecTipToWidth, initialTipDir));
|
|
230
|
+
const path = [...spine, ptTip];
|
|
231
|
+
let totalArcLength = 0;
|
|
232
|
+
for (let i = 1; i < path.length; i++) totalArcLength += vecMag(vecSub(path[i], path[i - 1]));
|
|
233
|
+
const minimumShaftLength = Math.max(EPSILON, totalArcLength * .01);
|
|
234
|
+
let distanceRemaining = clamp(requestedHeadLength, EPSILON, Math.max(EPSILON, totalArcLength - minimumShaftLength));
|
|
235
|
+
let ptBase = ptTip;
|
|
236
|
+
let remainingSpine = spine;
|
|
237
|
+
for (let i = path.length - 1; i > 0; i--) {
|
|
238
|
+
const segmentEnd = path[i];
|
|
239
|
+
const segmentStart = path[i - 1];
|
|
240
|
+
const segment = vecSub(segmentStart, segmentEnd);
|
|
241
|
+
const segmentLength = vecMag(segment);
|
|
242
|
+
if (segmentLength < 1e-6) continue;
|
|
243
|
+
if (distanceRemaining < segmentLength) {
|
|
244
|
+
ptBase = vecAdd(segmentEnd, vecScale(segment, distanceRemaining / segmentLength));
|
|
245
|
+
remainingSpine = path.slice(0, i);
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
distanceRemaining -= segmentLength;
|
|
249
|
+
}
|
|
250
|
+
const ptNeck = remainingSpine[remainingSpine.length - 1];
|
|
222
251
|
if (!ptNeck) return null;
|
|
223
252
|
const tipDir = vecNorm(vecSub(ptTip, ptNeck));
|
|
224
253
|
if (vecMag(tipDir) < 1e-6) return null;
|
|
225
|
-
const
|
|
226
|
-
const vecTipToWidth = vecSub(ptTip, ptWidth);
|
|
227
|
-
const maxHeadLength = Math.max(0, vecMag(vecSub(ptTip, ptNeck)) - .1);
|
|
228
|
-
const headLength = clamp(vecDot(vecTipToWidth, tipDir), EPSILON, maxHeadLength);
|
|
229
|
-
const ptBase = vecSub(ptTip, vecScale(tipDir, headLength));
|
|
254
|
+
const headLength = vecMag(vecSub(ptTip, ptBase));
|
|
230
255
|
const shaftHalfWidth = headHalfWidth * shaftRatio;
|
|
231
256
|
const perpDir = [-tipDir[1], tipDir[0]];
|
|
232
257
|
const outerLeft = vecAdd(ptBase, vecScale(perpDir, headHalfWidth));
|
|
@@ -234,7 +259,8 @@ function calculateSymbolGeometry(ptTip, ptWidth, spine, shaftRatio, roundedBends
|
|
|
234
259
|
const innerLeft = vecAdd(ptBase, vecScale(perpDir, shaftHalfWidth));
|
|
235
260
|
const innerRight = vecAdd(ptBase, vecScale(perpDir, -shaftHalfWidth));
|
|
236
261
|
const notchDepth = headLength * shaftRatio;
|
|
237
|
-
const
|
|
262
|
+
const safeNotchDepth = Math.min(notchDepth, headLength - EPSILON);
|
|
263
|
+
const innerTip = vecAdd(ptBase, vecScale(tipDir, safeNotchDepth));
|
|
238
264
|
const shaftEndCenter = ptBase;
|
|
239
265
|
const headRing = [
|
|
240
266
|
outerLeft,
|
|
@@ -245,7 +271,7 @@ function calculateSymbolGeometry(ptTip, ptWidth, spine, shaftRatio, roundedBends
|
|
|
245
271
|
innerLeft,
|
|
246
272
|
outerLeft
|
|
247
273
|
];
|
|
248
|
-
const fullSpine = [...
|
|
274
|
+
const fullSpine = [...remainingSpine, shaftEndCenter];
|
|
249
275
|
return {
|
|
250
276
|
shaftLeft: offsetPolyline(fullSpine, shaftHalfWidth, roundedBends, bendSegments),
|
|
251
277
|
shaftRight: offsetPolyline(fullSpine, -shaftHalfWidth, roundedBends, bendSegments),
|
|
@@ -1826,7 +1852,7 @@ function createAttackHelicopter(coordinates, options = {}) {
|
|
|
1826
1852
|
type: "FeatureCollection",
|
|
1827
1853
|
features: []
|
|
1828
1854
|
};
|
|
1829
|
-
const center = lineIntersection(pL, pIR, pR, pIL);
|
|
1855
|
+
const center = lineIntersection(pL, pIR, pR, pIL) ?? geometry.ptBase;
|
|
1830
1856
|
const features = [{
|
|
1831
1857
|
type: "Feature",
|
|
1832
1858
|
properties: {},
|
|
@@ -2338,15 +2364,18 @@ function closedCatmullRom(points, samples) {
|
|
|
2338
2364
|
}
|
|
2339
2365
|
//#endregion
|
|
2340
2366
|
//#region src/internal/area-echelon.ts
|
|
2341
|
-
/**
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2367
|
+
/**
|
|
2368
|
+
* Twice the ring's signed area (shoelace). Positive when the ring winds
|
|
2369
|
+
* counter-clockwise in projected (y-up) coordinates.
|
|
2370
|
+
*/
|
|
2371
|
+
function ringSignedArea2(verts) {
|
|
2372
|
+
let area2 = 0;
|
|
2373
|
+
for (let i = 0; i < verts.length - 1; i++) {
|
|
2374
|
+
const a = verts[i];
|
|
2375
|
+
const b = verts[i + 1];
|
|
2376
|
+
area2 += a[0] * b[1] - b[0] * a[1];
|
|
2348
2377
|
}
|
|
2349
|
-
return
|
|
2378
|
+
return area2;
|
|
2350
2379
|
}
|
|
2351
2380
|
/**
|
|
2352
2381
|
* Projects `positions` and returns a closed ring (first == last), optionally
|
|
@@ -2366,7 +2395,7 @@ function buildClosedRing(positions, smooth, smoothResolution, defaultSmoothResol
|
|
|
2366
2395
|
* projected y), the side opposite the front.
|
|
2367
2396
|
*/
|
|
2368
2397
|
function buildAreaPerimeter(verts) {
|
|
2369
|
-
const
|
|
2398
|
+
const ccw = ringSignedArea2(verts) > 0;
|
|
2370
2399
|
const segs = [];
|
|
2371
2400
|
let totalLength = 0;
|
|
2372
2401
|
let anchorTarget = 0;
|
|
@@ -2379,8 +2408,7 @@ function buildAreaPerimeter(verts) {
|
|
|
2379
2408
|
if (length < 1e-6) continue;
|
|
2380
2409
|
const along = vecNorm(edge);
|
|
2381
2410
|
const mid = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2];
|
|
2382
|
-
|
|
2383
|
-
if (perp[0] * (mid[0] - centroid[0]) + perp[1] * (mid[1] - centroid[1]) < 0) perp = [-perp[0], -perp[1]];
|
|
2411
|
+
const perp = ccw ? [along[1], -along[0]] : [-along[1], along[0]];
|
|
2384
2412
|
segs.push({
|
|
2385
2413
|
start: a,
|
|
2386
2414
|
along,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orbat-mapper/control-measures",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.7",
|
|
4
4
|
"description": "Library for drawing tactical graphics and control measures according to MIL-STD-2525 and APP-6 standards.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Orbat Mapper",
|