@orbat-mapper/control-measures 0.2.0-alpha.5 → 0.2.0-alpha.6

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.
@@ -23,6 +23,19 @@ interface ControlMeasureDrawRule {
23
23
  * `minimumUserPoints` (no early preview).
24
24
  */
25
25
  readonly minimumPreviewPoints?: number;
26
+ /**
27
+ * Opt a fixed-length draw into the standard dashed interaction guide. Fixed
28
+ * shapes suppress guides by default because their generator preview is
29
+ * normally sufficient. Use this when the guide communicates an incomplete
30
+ * construction state, such as Rectangle's P1-P2 baseline.
31
+ */
32
+ readonly showGuide?: boolean;
33
+ /**
34
+ * Convert raw draw points into the spine rendered by the interaction guide.
35
+ * Defaults to the raw points. A rule may return the first point again at the
36
+ * end when it needs to provide its own closed guide geometry.
37
+ */
38
+ guidePoints?(points: readonly Position[]): Position[];
26
39
  /**
27
40
  * Number of trailing slots in the canonical control-point array that are
28
41
  * NOT user-clicked spine vertices. For Axis1, this is 1 (the width handle
@@ -162,6 +175,18 @@ interface ControlMeasureDefinition<Id extends string, G extends ControlMeasureGe
162
175
  * ADR-0025.
163
176
  */
164
177
  previewSample?: PreviewSample<NonNullable<Parameters<G>[1]>>;
178
+ /**
179
+ * Pins orientation-derived defaults — options whose default value depends on
180
+ * the shape's current screen orientation (e.g. Battle Position's echelon
181
+ * anchor, which defaults to the bottom edge) — to their current concrete
182
+ * values. Returns an options patch to merge onto the working options, or
183
+ * `undefined` when there is nothing to freeze (already frozen, or nothing
184
+ * visible to pin). Called by edit hosts when a rotate gesture starts, so a
185
+ * subsequent rigid rotation of the control points preserves the rendered
186
+ * appearance instead of an orientation-relative default silently re-deriving
187
+ * against the new orientation. See ADR-0023.
188
+ */
189
+ freezeOrientation?: (controlPoints: Position[], options: NonNullable<Parameters<G>[1]>) => Partial<NonNullable<Parameters<G>[1]>> | undefined;
165
190
  }
166
191
  /**
167
192
  * A measure's representative preview input. Shared between the typed
@@ -315,6 +340,25 @@ interface BattlePositionOptions {
315
340
  * @default 0
316
341
  */
317
342
  echelonPosition?: number;
343
+ /**
344
+ * Absolute anchor for the echelon glyph, as a fraction of the total
345
+ * perimeter measured from the ring seam (the ring's first vertex), wrapped
346
+ * into `[0, 1)`. When omitted, the anchor is "auto": the bottom edge's
347
+ * midpoint (the side opposite the front), recomputed from the current
348
+ * geometry on every render — the long-standing default behavior.
349
+ * `echelonPosition` still applies on top of this anchor as a signed offset,
350
+ * exactly as it does against the auto anchor.
351
+ *
352
+ * Edit controllers freeze this from "auto" to a concrete fraction the
353
+ * moment a rotate gesture starts (see `freezeEchelonAnchor` /
354
+ * `freezeOrientationOptions`): the transform box rotates only the control
355
+ * points and re-renders, so without a pinned anchor the "bottom edge" would
356
+ * keep re-deriving against the rotated geometry and the glyph would jump to
357
+ * a different edge each time a new edge becomes lowest. Freezing the anchor
358
+ * first makes the rotation rigid — the glyph turns with the shape instead.
359
+ * See ADR-0023.
360
+ */
361
+ echelonAnchor?: number;
318
362
  /**
319
363
  * Meters-per-pixel at the current zoom/latitude. Stamped by the host when the
320
364
  * measure is screen-anchored; required to resolve `echelonSizePixels`.
@@ -1505,6 +1549,17 @@ interface RenderOptions {
1505
1549
  */
1506
1550
  declare function renderControlMeasure<K extends ControlMeasureKind>(cm: ControlMeasure<K>, opts?: RenderOptions): ControlMeasureRender;
1507
1551
  //#endregion
1552
+ //#region src/freeze-orientation.d.ts
1553
+ /**
1554
+ * Dispatches to a measure kind's `freezeOrientation` hook (see
1555
+ * {@link import("./define").ControlMeasureDefinition.freezeOrientation}),
1556
+ * pinning orientation-derived option defaults to their current concrete
1557
+ * values ahead of a rigid rotation of `controlPoints`. Returns `undefined`
1558
+ * when the kind declares no hook, or when the hook itself finds nothing to
1559
+ * freeze. Edit hosts call this when a rotate gesture starts (ADR-0023).
1560
+ */
1561
+ declare function freezeOrientationOptions<K extends ControlMeasureKind>(kind: K, controlPoints: Position[], options: OptionsByKind[K] | undefined): Partial<OptionsByKind[K]> | undefined;
1562
+ //#endregion
1508
1563
  //#region src/styleResolver.d.ts
1509
1564
  /**
1510
1565
  * Three-layer style precedence for `renderControlMeasure`.
@@ -1767,4 +1822,4 @@ interface TacticalArrowOptions {
1767
1822
  */
1768
1823
  declare const DEFAULT_TACTICAL_ARROW_OPTIONS: Required<TacticalArrowOptions>;
1769
1824
  //#endregion
1770
- export { getControlMeasureMetadataByValue as $, GenericLineOptions as $t, getMetersPerPixel as A, BypassOptions as At, FeaturePartProps as B, DEFAULT_SUPPORT_BY_FIRE_OPTIONS as Bt, snapToMidpointPerpendicular as C, DEFAULT_ANTITANK_DITCH_OPTIONS as Ct, BaselineFrameOrigin as D, DEFAULT_CLEAR_OPTIONS as Dt, BaselineFrameOptions as E, ClearOptions as Et, resolveStyleHints as F, DEFAULT_BLOCK_MISSION_TASK_OPTIONS as Ft, isKind as G, DEFAULT_AIRBORNE_ATTACK_OPTIONS as Gt, controlMeasureIdFromFeature as H, AttackHelicopterOptions as Ht, RenderOptions as I, DEFAULT_FLOT_OPTIONS as It, CONTROL_MEASURE_METADATA as J, DEFAULT_GENERIC_RECTANGLE_OPTIONS as Jt, ControlMeasureStyle as K, DEFAULT_GENERIC_CIRCLE_OPTIONS as Kt, renderControlMeasure as L, FLOTOptions as Lt, SimpleStyleProps as M, BreachOptions as Mt, SimpleStyleRender as N, DEFAULT_BREACH_OPTIONS as Nt, createBaselineFrame as O, CanalizeOptions as Ot, toSimpleStyle as P, BlockMissionTaskOptions as Pt, getControlMeasureMetadata as Q, DEFAULT_GENERIC_LINE_OPTIONS as Qt, ControlMeasureRender as R, AttackByFireOptions as Rt, pointOnMidpointPerpendicularAxis as S, ControlMeasureDrawRule as Sn, AntitankDitchOptions as St, BaselineFrameNormal as T, DelayOptions as Tt, ControlMeasure as U, DEFAULT_ATTACK_HELICOPTER_OPTIONS as Ut, StyleHints as V, SupportByFireOptions as Vt, cloneControlMeasure as W, AirborneAttackOptions as Wt, ControlMeasureKind as X, DEFAULT_GENERIC_POLYGON_OPTIONS as Xt, ControlMeasureId as Y, GenericRectangleOptions as Yt, OptionsByKind as Z, GenericPolygonOptions as Zt, blockDrawRule as _, ControlMeasureGeometry as _n, FortifiedAreaOptions as _t, rectangleDrawRule as a, computeInitialWidthPoint as an, ObstacleBypassDifficultOptions as at, createMidpointPerpendicularDrawRule as b, ParamDescriptor as bn, AntitankWallOptions as bt, line24DrawRule as c, unproject as cn, DEFAULT_TURN_OPTIONS as ct, line1DrawRule as d, DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS as dn, FixOptions as dt, DEFAULT_SUPPORTING_ATTACK_OPTIONS as en, getDefaultOptions as et, ambushDrawRule as f, FinalProtectiveFireOptions as fn, DEFAULT_DISRUPT_OPTIONS as ft, disruptDrawRule as g, StrongPointOptions as gn, DEFAULT_FORTIFIED_AREA_OPTIONS as gt, centerRadiusDrawRule as h, DEFAULT_STRONG_POINT_OPTIONS as hn, DEFAULT_BLOCK_OPTIONS as ht, DEFAULT_AMBUSH_OPTIONS as i, calculateMetrics as in, DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS as it, roundToFixed as j, DEFAULT_BYPASS_OPTIONS as jt, EPSILON as k, DEFAULT_CANALIZE_OPTIONS as kt, line23DrawRule as l, DEFAULT_ENCIRCLEMENT_OPTIONS as ln, TurnOptions as lt, point12DrawRule as m, PrincipalDirectionOfFireOptions as mn, BlockOptions as mt, TacticalArrowOptions as n, DEFAULT_MAIN_ATTACK_OPTIONS as nn, DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS as nt, axis1DrawRule as o, Point2D as on, DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS as ot, attackByFireDrawRule as p, DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS as pn, DisruptOptions as pt, CONTROL_MEASURE_IDS as q, GenericCircleOptions as qt, AmbushOptions as r, MainAttackOptions as rn, ObstacleBypassImpossibleOptions as rt, supportByFireDrawRule as s, project as sn, ObstacleBypassEasyOptions as st, DEFAULT_TACTICAL_ARROW_OPTIONS as t, SupportingAttackOptions as tn, listControlMeasureMetadata as tt, turnDrawRule as u, EncirclementOptions as un, DEFAULT_FIX_OPTIONS as ut, MidpointPerpendicularDrawRuleOptions as v, ControlMeasureGeometryType as vn, DEFAULT_FORTIFIED_LINE_OPTIONS as vt, BaselineFrame as w, DEFAULT_DELAY_OPTIONS as wt, getMidpointPerpendicularSignedDistance as x, AnchorTransformEvent as xn, DEFAULT_ANTITANK_WALL_OPTIONS as xt, computeDefaultMidpointPerpendicularPoint as y, ControlMeasureMetadata as yn, FortifiedLineOptions as yt, ControlMeasureSnapshot as z, DEFAULT_ATTACK_BY_FIRE_OPTIONS as zt };
1825
+ export { getControlMeasureMetadata as $, DEFAULT_GENERIC_LINE_OPTIONS as $t, getMetersPerPixel as A, DEFAULT_CANALIZE_OPTIONS as At, ControlMeasureSnapshot as B, DEFAULT_ATTACK_BY_FIRE_OPTIONS as Bt, snapToMidpointPerpendicular as C, ControlMeasureDrawRule as Cn, AntitankDitchOptions as Ct, BaselineFrameOrigin as D, ClearOptions as Dt, BaselineFrameOptions as E, DelayOptions as Et, resolveStyleHints as F, BlockMissionTaskOptions as Ft, cloneControlMeasure as G, AirborneAttackOptions as Gt, StyleHints as H, SupportByFireOptions as Ht, freezeOrientationOptions as I, DEFAULT_BLOCK_MISSION_TASK_OPTIONS as It, CONTROL_MEASURE_IDS as J, GenericCircleOptions as Jt, isKind as K, DEFAULT_AIRBORNE_ATTACK_OPTIONS as Kt, RenderOptions as L, DEFAULT_FLOT_OPTIONS as Lt, SimpleStyleProps as M, DEFAULT_BYPASS_OPTIONS as Mt, SimpleStyleRender as N, BreachOptions as Nt, createBaselineFrame as O, DEFAULT_CLEAR_OPTIONS as Ot, toSimpleStyle as P, DEFAULT_BREACH_OPTIONS as Pt, OptionsByKind as Q, GenericPolygonOptions as Qt, renderControlMeasure as R, FLOTOptions as Rt, pointOnMidpointPerpendicularAxis as S, AnchorTransformEvent as Sn, DEFAULT_ANTITANK_WALL_OPTIONS as St, BaselineFrameNormal as T, DEFAULT_DELAY_OPTIONS as Tt, controlMeasureIdFromFeature as U, AttackHelicopterOptions as Ut, FeaturePartProps as V, DEFAULT_SUPPORT_BY_FIRE_OPTIONS as Vt, ControlMeasure as W, DEFAULT_ATTACK_HELICOPTER_OPTIONS as Wt, ControlMeasureId as X, GenericRectangleOptions as Xt, CONTROL_MEASURE_METADATA as Y, DEFAULT_GENERIC_RECTANGLE_OPTIONS as Yt, ControlMeasureKind as Z, DEFAULT_GENERIC_POLYGON_OPTIONS as Zt, blockDrawRule as _, StrongPointOptions as _n, DEFAULT_FORTIFIED_AREA_OPTIONS as _t, rectangleDrawRule as a, calculateMetrics as an, DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS as at, createMidpointPerpendicularDrawRule as b, ControlMeasureMetadata as bn, FortifiedLineOptions as bt, line24DrawRule as c, project as cn, ObstacleBypassEasyOptions as ct, line1DrawRule as d, EncirclementOptions as dn, DEFAULT_FIX_OPTIONS as dt, GenericLineOptions as en, getControlMeasureMetadataByValue as et, ambushDrawRule as f, DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS as fn, FixOptions as ft, disruptDrawRule as g, DEFAULT_STRONG_POINT_OPTIONS as gn, DEFAULT_BLOCK_OPTIONS as gt, centerRadiusDrawRule as h, PrincipalDirectionOfFireOptions as hn, BlockOptions as ht, DEFAULT_AMBUSH_OPTIONS as i, MainAttackOptions as in, ObstacleBypassImpossibleOptions as it, roundToFixed as j, BypassOptions as jt, EPSILON as k, CanalizeOptions as kt, line23DrawRule as l, unproject as ln, DEFAULT_TURN_OPTIONS as lt, point12DrawRule as m, DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS as mn, DisruptOptions as mt, TacticalArrowOptions as n, SupportingAttackOptions as nn, listControlMeasureMetadata as nt, axis1DrawRule as o, computeInitialWidthPoint as on, ObstacleBypassDifficultOptions as ot, attackByFireDrawRule as p, FinalProtectiveFireOptions as pn, DEFAULT_DISRUPT_OPTIONS as pt, ControlMeasureStyle as q, DEFAULT_GENERIC_CIRCLE_OPTIONS as qt, AmbushOptions as r, DEFAULT_MAIN_ATTACK_OPTIONS as rn, DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS as rt, supportByFireDrawRule as s, Point2D as sn, DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS as st, DEFAULT_TACTICAL_ARROW_OPTIONS as t, DEFAULT_SUPPORTING_ATTACK_OPTIONS as tn, getDefaultOptions as tt, turnDrawRule as u, DEFAULT_ENCIRCLEMENT_OPTIONS as un, TurnOptions as ut, MidpointPerpendicularDrawRuleOptions as v, ControlMeasureGeometry as vn, FortifiedAreaOptions as vt, BaselineFrame as w, DEFAULT_ANTITANK_DITCH_OPTIONS as wt, getMidpointPerpendicularSignedDistance as x, ParamDescriptor as xn, AntitankWallOptions as xt, computeDefaultMidpointPerpendicularPoint as y, ControlMeasureGeometryType as yn, DEFAULT_FORTIFIED_LINE_OPTIONS as yt, ControlMeasureRender as z, AttackByFireOptions as zt };
package/dist/index.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { $ as getControlMeasureMetadataByValue, $t as GenericLineOptions, A as getMetersPerPixel, At as BypassOptions, B as FeaturePartProps, Bt as DEFAULT_SUPPORT_BY_FIRE_OPTIONS, C as snapToMidpointPerpendicular, Ct as DEFAULT_ANTITANK_DITCH_OPTIONS, D as BaselineFrameOrigin, Dt as DEFAULT_CLEAR_OPTIONS, E as BaselineFrameOptions, Et as ClearOptions, F as resolveStyleHints, Ft as DEFAULT_BLOCK_MISSION_TASK_OPTIONS, G as isKind, Gt as DEFAULT_AIRBORNE_ATTACK_OPTIONS, H as controlMeasureIdFromFeature, Ht as AttackHelicopterOptions, I as RenderOptions, It as DEFAULT_FLOT_OPTIONS, J as CONTROL_MEASURE_METADATA, Jt as DEFAULT_GENERIC_RECTANGLE_OPTIONS, K as ControlMeasureStyle, Kt as DEFAULT_GENERIC_CIRCLE_OPTIONS, L as renderControlMeasure, Lt as FLOTOptions, M as SimpleStyleProps, Mt as BreachOptions, N as SimpleStyleRender, Nt as DEFAULT_BREACH_OPTIONS, O as createBaselineFrame, Ot as CanalizeOptions, P as toSimpleStyle, Pt as BlockMissionTaskOptions, Q as getControlMeasureMetadata, Qt as DEFAULT_GENERIC_LINE_OPTIONS, R as ControlMeasureRender, Rt as AttackByFireOptions, S as pointOnMidpointPerpendicularAxis, Sn as ControlMeasureDrawRule, St as AntitankDitchOptions, T as BaselineFrameNormal, Tt as DelayOptions, U as ControlMeasure, Ut as DEFAULT_ATTACK_HELICOPTER_OPTIONS, V as StyleHints, Vt as SupportByFireOptions, W as cloneControlMeasure, Wt as AirborneAttackOptions, X as ControlMeasureKind, Xt as DEFAULT_GENERIC_POLYGON_OPTIONS, Y as ControlMeasureId, Yt as GenericRectangleOptions, Z as OptionsByKind, Zt as GenericPolygonOptions, _ as blockDrawRule, _n as ControlMeasureGeometry, _t as FortifiedAreaOptions, a as rectangleDrawRule, an as computeInitialWidthPoint, at as ObstacleBypassDifficultOptions, b as createMidpointPerpendicularDrawRule, bn as ParamDescriptor, bt as AntitankWallOptions, c as line24DrawRule, cn as unproject, ct as DEFAULT_TURN_OPTIONS, d as line1DrawRule, dn as DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, dt as FixOptions, en as DEFAULT_SUPPORTING_ATTACK_OPTIONS, et as getDefaultOptions, f as ambushDrawRule, fn as FinalProtectiveFireOptions, ft as DEFAULT_DISRUPT_OPTIONS, g as disruptDrawRule, gn as StrongPointOptions, gt as DEFAULT_FORTIFIED_AREA_OPTIONS, h as centerRadiusDrawRule, hn as DEFAULT_STRONG_POINT_OPTIONS, ht as DEFAULT_BLOCK_OPTIONS, i as DEFAULT_AMBUSH_OPTIONS, in as calculateMetrics, it as DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, j as roundToFixed, jt as DEFAULT_BYPASS_OPTIONS, k as EPSILON, kt as DEFAULT_CANALIZE_OPTIONS, l as line23DrawRule, ln as DEFAULT_ENCIRCLEMENT_OPTIONS, lt as TurnOptions, m as point12DrawRule, mn as PrincipalDirectionOfFireOptions, mt as BlockOptions, n as TacticalArrowOptions, nn as DEFAULT_MAIN_ATTACK_OPTIONS, nt as DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, o as axis1DrawRule, on as Point2D, ot as DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, p as attackByFireDrawRule, pn as DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, pt as DisruptOptions, q as CONTROL_MEASURE_IDS, qt as GenericCircleOptions, r as AmbushOptions, rn as MainAttackOptions, rt as ObstacleBypassImpossibleOptions, s as supportByFireDrawRule, sn as project, st as ObstacleBypassEasyOptions, t as DEFAULT_TACTICAL_ARROW_OPTIONS, tn as SupportingAttackOptions, tt as listControlMeasureMetadata, u as turnDrawRule, un as EncirclementOptions, ut as DEFAULT_FIX_OPTIONS, v as MidpointPerpendicularDrawRuleOptions, vn as ControlMeasureGeometryType, vt as DEFAULT_FORTIFIED_LINE_OPTIONS, w as BaselineFrame, wt as DEFAULT_DELAY_OPTIONS, x as getMidpointPerpendicularSignedDistance, xn as AnchorTransformEvent, xt as DEFAULT_ANTITANK_WALL_OPTIONS, y as computeDefaultMidpointPerpendicularPoint, yn as ControlMeasureMetadata, yt as FortifiedLineOptions, z as ControlMeasureSnapshot, zt as DEFAULT_ATTACK_BY_FIRE_OPTIONS } from "./index-Ddt-obht.mjs";
2
- export { type AirborneAttackOptions, type AmbushOptions, type AnchorTransformEvent, type AntitankDitchOptions, type AntitankWallOptions, type AttackByFireOptions, type AttackHelicopterOptions, type BaselineFrame, type BaselineFrameNormal, type BaselineFrameOptions, type BaselineFrameOrigin, type BlockMissionTaskOptions, type BlockOptions, type BreachOptions, type BypassOptions, CONTROL_MEASURE_IDS, CONTROL_MEASURE_METADATA, type CanalizeOptions, type ClearOptions, type ControlMeasure, type ControlMeasureDrawRule, type ControlMeasureGeometry, type ControlMeasureGeometryType, type ControlMeasureId, type ControlMeasureKind, type ControlMeasureMetadata, type ControlMeasureRender, type ControlMeasureSnapshot, type ControlMeasureStyle, DEFAULT_AIRBORNE_ATTACK_OPTIONS, DEFAULT_AMBUSH_OPTIONS, DEFAULT_ANTITANK_DITCH_OPTIONS, DEFAULT_ANTITANK_WALL_OPTIONS, DEFAULT_ATTACK_BY_FIRE_OPTIONS, DEFAULT_ATTACK_HELICOPTER_OPTIONS, DEFAULT_BLOCK_MISSION_TASK_OPTIONS, DEFAULT_BLOCK_OPTIONS, DEFAULT_BREACH_OPTIONS, DEFAULT_BYPASS_OPTIONS, DEFAULT_CANALIZE_OPTIONS, DEFAULT_CLEAR_OPTIONS, DEFAULT_DELAY_OPTIONS, DEFAULT_DISRUPT_OPTIONS, DEFAULT_ENCIRCLEMENT_OPTIONS, DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, DEFAULT_FIX_OPTIONS, DEFAULT_FLOT_OPTIONS, DEFAULT_FORTIFIED_AREA_OPTIONS, DEFAULT_FORTIFIED_LINE_OPTIONS, DEFAULT_GENERIC_CIRCLE_OPTIONS, DEFAULT_GENERIC_LINE_OPTIONS, DEFAULT_GENERIC_POLYGON_OPTIONS, DEFAULT_GENERIC_RECTANGLE_OPTIONS, DEFAULT_MAIN_ATTACK_OPTIONS, DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, DEFAULT_STRONG_POINT_OPTIONS, DEFAULT_SUPPORTING_ATTACK_OPTIONS, DEFAULT_SUPPORT_BY_FIRE_OPTIONS, DEFAULT_TACTICAL_ARROW_OPTIONS, DEFAULT_TURN_OPTIONS, type DelayOptions, type DisruptOptions, EPSILON, type EncirclementOptions, type FLOTOptions, type FeaturePartProps, type FinalProtectiveFireOptions, type FixOptions, type FortifiedAreaOptions, type FortifiedLineOptions, type GenericCircleOptions, type GenericLineOptions, type GenericPolygonOptions, type GenericRectangleOptions, type MainAttackOptions, type MidpointPerpendicularDrawRuleOptions, type ObstacleBypassDifficultOptions, type ObstacleBypassEasyOptions, type ObstacleBypassImpossibleOptions, type OptionsByKind, type ParamDescriptor, type Point2D, type PrincipalDirectionOfFireOptions, type RenderOptions, type SimpleStyleProps, type SimpleStyleRender, type StrongPointOptions, type StyleHints, type SupportByFireOptions, type SupportingAttackOptions, type TacticalArrowOptions, type TurnOptions, ambushDrawRule, attackByFireDrawRule, axis1DrawRule, blockDrawRule, calculateMetrics, centerRadiusDrawRule, cloneControlMeasure, computeDefaultMidpointPerpendicularPoint, computeInitialWidthPoint, controlMeasureIdFromFeature, createBaselineFrame, createMidpointPerpendicularDrawRule, disruptDrawRule, getControlMeasureMetadata, getControlMeasureMetadataByValue, getDefaultOptions, getMetersPerPixel, getMidpointPerpendicularSignedDistance, isKind, line1DrawRule, line23DrawRule, line24DrawRule, listControlMeasureMetadata, point12DrawRule, pointOnMidpointPerpendicularAxis, project, rectangleDrawRule, renderControlMeasure, resolveStyleHints, roundToFixed, snapToMidpointPerpendicular, supportByFireDrawRule, toSimpleStyle, turnDrawRule, unproject };
1
+ import { $ as getControlMeasureMetadata, $t as DEFAULT_GENERIC_LINE_OPTIONS, A as getMetersPerPixel, At as DEFAULT_CANALIZE_OPTIONS, B as ControlMeasureSnapshot, Bt as DEFAULT_ATTACK_BY_FIRE_OPTIONS, C as snapToMidpointPerpendicular, Cn as ControlMeasureDrawRule, Ct as AntitankDitchOptions, D as BaselineFrameOrigin, Dt as ClearOptions, E as BaselineFrameOptions, Et as DelayOptions, F as resolveStyleHints, Ft as BlockMissionTaskOptions, G as cloneControlMeasure, Gt as AirborneAttackOptions, H as StyleHints, Ht as SupportByFireOptions, I as freezeOrientationOptions, It as DEFAULT_BLOCK_MISSION_TASK_OPTIONS, J as CONTROL_MEASURE_IDS, Jt as GenericCircleOptions, K as isKind, Kt as DEFAULT_AIRBORNE_ATTACK_OPTIONS, L as RenderOptions, Lt as DEFAULT_FLOT_OPTIONS, M as SimpleStyleProps, Mt as DEFAULT_BYPASS_OPTIONS, N as SimpleStyleRender, Nt as BreachOptions, O as createBaselineFrame, Ot as DEFAULT_CLEAR_OPTIONS, P as toSimpleStyle, Pt as DEFAULT_BREACH_OPTIONS, Q as OptionsByKind, Qt as GenericPolygonOptions, R as renderControlMeasure, Rt as FLOTOptions, S as pointOnMidpointPerpendicularAxis, Sn as AnchorTransformEvent, St as DEFAULT_ANTITANK_WALL_OPTIONS, T as BaselineFrameNormal, Tt as DEFAULT_DELAY_OPTIONS, U as controlMeasureIdFromFeature, Ut as AttackHelicopterOptions, V as FeaturePartProps, Vt as DEFAULT_SUPPORT_BY_FIRE_OPTIONS, W as ControlMeasure, Wt as DEFAULT_ATTACK_HELICOPTER_OPTIONS, X as ControlMeasureId, Xt as GenericRectangleOptions, Y as CONTROL_MEASURE_METADATA, Yt as DEFAULT_GENERIC_RECTANGLE_OPTIONS, Z as ControlMeasureKind, Zt as DEFAULT_GENERIC_POLYGON_OPTIONS, _ as blockDrawRule, _n as StrongPointOptions, _t as DEFAULT_FORTIFIED_AREA_OPTIONS, a as rectangleDrawRule, an as calculateMetrics, at as DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, b as createMidpointPerpendicularDrawRule, bn as ControlMeasureMetadata, bt as FortifiedLineOptions, c as line24DrawRule, cn as project, ct as ObstacleBypassEasyOptions, d as line1DrawRule, dn as EncirclementOptions, dt as DEFAULT_FIX_OPTIONS, en as GenericLineOptions, et as getControlMeasureMetadataByValue, f as ambushDrawRule, fn as DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, ft as FixOptions, g as disruptDrawRule, gn as DEFAULT_STRONG_POINT_OPTIONS, gt as DEFAULT_BLOCK_OPTIONS, h as centerRadiusDrawRule, hn as PrincipalDirectionOfFireOptions, ht as BlockOptions, i as DEFAULT_AMBUSH_OPTIONS, in as MainAttackOptions, it as ObstacleBypassImpossibleOptions, j as roundToFixed, jt as BypassOptions, k as EPSILON, kt as CanalizeOptions, l as line23DrawRule, ln as unproject, lt as DEFAULT_TURN_OPTIONS, m as point12DrawRule, mn as DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, mt as DisruptOptions, n as TacticalArrowOptions, nn as SupportingAttackOptions, nt as listControlMeasureMetadata, o as axis1DrawRule, on as computeInitialWidthPoint, ot as ObstacleBypassDifficultOptions, p as attackByFireDrawRule, pn as FinalProtectiveFireOptions, pt as DEFAULT_DISRUPT_OPTIONS, q as ControlMeasureStyle, qt as DEFAULT_GENERIC_CIRCLE_OPTIONS, r as AmbushOptions, rn as DEFAULT_MAIN_ATTACK_OPTIONS, rt as DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, s as supportByFireDrawRule, sn as Point2D, st as DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, t as DEFAULT_TACTICAL_ARROW_OPTIONS, tn as DEFAULT_SUPPORTING_ATTACK_OPTIONS, tt as getDefaultOptions, u as turnDrawRule, un as DEFAULT_ENCIRCLEMENT_OPTIONS, ut as TurnOptions, v as MidpointPerpendicularDrawRuleOptions, vn as ControlMeasureGeometry, vt as FortifiedAreaOptions, w as BaselineFrame, wt as DEFAULT_ANTITANK_DITCH_OPTIONS, x as getMidpointPerpendicularSignedDistance, xn as ParamDescriptor, xt as AntitankWallOptions, y as computeDefaultMidpointPerpendicularPoint, yn as ControlMeasureGeometryType, yt as DEFAULT_FORTIFIED_LINE_OPTIONS, z as ControlMeasureRender, zt as AttackByFireOptions } from "./index-DUGzYzPy.mjs";
2
+ export { type AirborneAttackOptions, type AmbushOptions, type AnchorTransformEvent, type AntitankDitchOptions, type AntitankWallOptions, type AttackByFireOptions, type AttackHelicopterOptions, type BaselineFrame, type BaselineFrameNormal, type BaselineFrameOptions, type BaselineFrameOrigin, type BlockMissionTaskOptions, type BlockOptions, type BreachOptions, type BypassOptions, CONTROL_MEASURE_IDS, CONTROL_MEASURE_METADATA, type CanalizeOptions, type ClearOptions, type ControlMeasure, type ControlMeasureDrawRule, type ControlMeasureGeometry, type ControlMeasureGeometryType, type ControlMeasureId, type ControlMeasureKind, type ControlMeasureMetadata, type ControlMeasureRender, type ControlMeasureSnapshot, type ControlMeasureStyle, DEFAULT_AIRBORNE_ATTACK_OPTIONS, DEFAULT_AMBUSH_OPTIONS, DEFAULT_ANTITANK_DITCH_OPTIONS, DEFAULT_ANTITANK_WALL_OPTIONS, DEFAULT_ATTACK_BY_FIRE_OPTIONS, DEFAULT_ATTACK_HELICOPTER_OPTIONS, DEFAULT_BLOCK_MISSION_TASK_OPTIONS, DEFAULT_BLOCK_OPTIONS, DEFAULT_BREACH_OPTIONS, DEFAULT_BYPASS_OPTIONS, DEFAULT_CANALIZE_OPTIONS, DEFAULT_CLEAR_OPTIONS, DEFAULT_DELAY_OPTIONS, DEFAULT_DISRUPT_OPTIONS, DEFAULT_ENCIRCLEMENT_OPTIONS, DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, DEFAULT_FIX_OPTIONS, DEFAULT_FLOT_OPTIONS, DEFAULT_FORTIFIED_AREA_OPTIONS, DEFAULT_FORTIFIED_LINE_OPTIONS, DEFAULT_GENERIC_CIRCLE_OPTIONS, DEFAULT_GENERIC_LINE_OPTIONS, DEFAULT_GENERIC_POLYGON_OPTIONS, DEFAULT_GENERIC_RECTANGLE_OPTIONS, DEFAULT_MAIN_ATTACK_OPTIONS, DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, DEFAULT_STRONG_POINT_OPTIONS, DEFAULT_SUPPORTING_ATTACK_OPTIONS, DEFAULT_SUPPORT_BY_FIRE_OPTIONS, DEFAULT_TACTICAL_ARROW_OPTIONS, DEFAULT_TURN_OPTIONS, type DelayOptions, type DisruptOptions, EPSILON, type EncirclementOptions, type FLOTOptions, type FeaturePartProps, type FinalProtectiveFireOptions, type FixOptions, type FortifiedAreaOptions, type FortifiedLineOptions, type GenericCircleOptions, type GenericLineOptions, type GenericPolygonOptions, type GenericRectangleOptions, type MainAttackOptions, type MidpointPerpendicularDrawRuleOptions, type ObstacleBypassDifficultOptions, type ObstacleBypassEasyOptions, type ObstacleBypassImpossibleOptions, type OptionsByKind, type ParamDescriptor, type Point2D, type PrincipalDirectionOfFireOptions, type RenderOptions, type SimpleStyleProps, type SimpleStyleRender, type StrongPointOptions, type StyleHints, type SupportByFireOptions, type SupportingAttackOptions, type TacticalArrowOptions, type TurnOptions, ambushDrawRule, attackByFireDrawRule, axis1DrawRule, blockDrawRule, calculateMetrics, centerRadiusDrawRule, cloneControlMeasure, computeDefaultMidpointPerpendicularPoint, computeInitialWidthPoint, controlMeasureIdFromFeature, createBaselineFrame, createMidpointPerpendicularDrawRule, disruptDrawRule, freezeOrientationOptions, getControlMeasureMetadata, getControlMeasureMetadataByValue, getDefaultOptions, getMetersPerPixel, getMidpointPerpendicularSignedDistance, isKind, line1DrawRule, line23DrawRule, line24DrawRule, listControlMeasureMetadata, point12DrawRule, pointOnMidpointPerpendicularAxis, project, rectangleDrawRule, renderControlMeasure, resolveStyleHints, roundToFixed, snapToMidpointPerpendicular, supportByFireDrawRule, toSimpleStyle, turnDrawRule, unproject };
package/dist/index.mjs CHANGED
@@ -1,4 +1,19 @@
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, 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-CDCoQlZ-.mjs";
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-D5NKuws0.mjs";
2
+ //#region src/freeze-orientation.ts
3
+ /**
4
+ * Dispatches to a measure kind's `freezeOrientation` hook (see
5
+ * {@link import("./define").ControlMeasureDefinition.freezeOrientation}),
6
+ * pinning orientation-derived option defaults to their current concrete
7
+ * values ahead of a rigid rotation of `controlPoints`. Returns `undefined`
8
+ * when the kind declares no hook, or when the hook itself finds nothing to
9
+ * freeze. Edit hosts call this when a rotate gesture starts (ADR-0023).
10
+ */
11
+ function freezeOrientationOptions(kind, controlPoints, options) {
12
+ const definition = DEFINITIONS[kind];
13
+ if (!definition.freezeOrientation) return void 0;
14
+ return definition.freezeOrientation(controlPoints, options ?? {});
15
+ }
16
+ //#endregion
2
17
  //#region src/instance.ts
3
18
  function isKind(cm, kind) {
4
19
  return cm.kind === kind;
@@ -99,4 +114,4 @@ function toHexChannel(value) {
99
114
  return Math.max(0, Math.min(255, Math.round(value))).toString(16).padStart(2, "0");
100
115
  }
101
116
  //#endregion
102
- export { CONTROL_MEASURE_IDS, CONTROL_MEASURE_METADATA, DEFAULT_AIRBORNE_ATTACK_OPTIONS, DEFAULT_AMBUSH_OPTIONS, DEFAULT_ANTITANK_DITCH_OPTIONS, DEFAULT_ANTITANK_WALL_OPTIONS, DEFAULT_ATTACK_BY_FIRE_OPTIONS, DEFAULT_ATTACK_HELICOPTER_OPTIONS, DEFAULT_BLOCK_MISSION_TASK_OPTIONS, DEFAULT_BLOCK_OPTIONS, DEFAULT_BREACH_OPTIONS, DEFAULT_BYPASS_OPTIONS, DEFAULT_CANALIZE_OPTIONS, DEFAULT_CLEAR_OPTIONS, DEFAULT_DELAY_OPTIONS, DEFAULT_DISRUPT_OPTIONS, DEFAULT_ENCIRCLEMENT_OPTIONS, DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, DEFAULT_FIX_OPTIONS, DEFAULT_FLOT_OPTIONS, DEFAULT_FORTIFIED_AREA_OPTIONS, DEFAULT_FORTIFIED_LINE_OPTIONS, DEFAULT_GENERIC_CIRCLE_OPTIONS, DEFAULT_GENERIC_LINE_OPTIONS, DEFAULT_GENERIC_POLYGON_OPTIONS, DEFAULT_GENERIC_RECTANGLE_OPTIONS, DEFAULT_MAIN_ATTACK_OPTIONS, DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, DEFAULT_STRONG_POINT_OPTIONS, DEFAULT_SUPPORTING_ATTACK_OPTIONS, DEFAULT_SUPPORT_BY_FIRE_OPTIONS, DEFAULT_TACTICAL_ARROW_OPTIONS, DEFAULT_TURN_OPTIONS, EPSILON, ambushDrawRule, attackByFireDrawRule, axis1DrawRule, blockDrawRule, calculateMetrics, centerRadiusDrawRule, cloneControlMeasure, computeDefaultMidpointPerpendicularPoint, computeInitialWidthPoint, controlMeasureIdFromFeature, createBaselineFrame, createMidpointPerpendicularDrawRule, disruptDrawRule, getControlMeasureMetadata, getControlMeasureMetadataByValue, getDefaultOptions, getMetersPerPixel, getMidpointPerpendicularSignedDistance, isKind, line1DrawRule, line23DrawRule, line24DrawRule, listControlMeasureMetadata, point12DrawRule, pointOnMidpointPerpendicularAxis, project, rectangleDrawRule, renderControlMeasure, resolveStyleHints, roundToFixed, snapToMidpointPerpendicular, supportByFireDrawRule, toSimpleStyle, turnDrawRule, unproject };
117
+ export { CONTROL_MEASURE_IDS, CONTROL_MEASURE_METADATA, DEFAULT_AIRBORNE_ATTACK_OPTIONS, DEFAULT_AMBUSH_OPTIONS, DEFAULT_ANTITANK_DITCH_OPTIONS, DEFAULT_ANTITANK_WALL_OPTIONS, DEFAULT_ATTACK_BY_FIRE_OPTIONS, DEFAULT_ATTACK_HELICOPTER_OPTIONS, DEFAULT_BLOCK_MISSION_TASK_OPTIONS, DEFAULT_BLOCK_OPTIONS, DEFAULT_BREACH_OPTIONS, DEFAULT_BYPASS_OPTIONS, DEFAULT_CANALIZE_OPTIONS, DEFAULT_CLEAR_OPTIONS, DEFAULT_DELAY_OPTIONS, DEFAULT_DISRUPT_OPTIONS, DEFAULT_ENCIRCLEMENT_OPTIONS, DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, DEFAULT_FIX_OPTIONS, DEFAULT_FLOT_OPTIONS, DEFAULT_FORTIFIED_AREA_OPTIONS, DEFAULT_FORTIFIED_LINE_OPTIONS, DEFAULT_GENERIC_CIRCLE_OPTIONS, DEFAULT_GENERIC_LINE_OPTIONS, DEFAULT_GENERIC_POLYGON_OPTIONS, DEFAULT_GENERIC_RECTANGLE_OPTIONS, DEFAULT_MAIN_ATTACK_OPTIONS, DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, DEFAULT_STRONG_POINT_OPTIONS, DEFAULT_SUPPORTING_ATTACK_OPTIONS, DEFAULT_SUPPORT_BY_FIRE_OPTIONS, DEFAULT_TACTICAL_ARROW_OPTIONS, DEFAULT_TURN_OPTIONS, EPSILON, ambushDrawRule, attackByFireDrawRule, axis1DrawRule, blockDrawRule, calculateMetrics, centerRadiusDrawRule, cloneControlMeasure, computeDefaultMidpointPerpendicularPoint, computeInitialWidthPoint, controlMeasureIdFromFeature, createBaselineFrame, createMidpointPerpendicularDrawRule, disruptDrawRule, freezeOrientationOptions, getControlMeasureMetadata, getControlMeasureMetadataByValue, getDefaultOptions, getMetersPerPixel, getMidpointPerpendicularSignedDistance, isKind, line1DrawRule, line23DrawRule, line24DrawRule, listControlMeasureMetadata, point12DrawRule, pointOnMidpointPerpendicularAxis, project, rectangleDrawRule, renderControlMeasure, resolveStyleHints, roundToFixed, snapToMidpointPerpendicular, supportByFireDrawRule, toSimpleStyle, turnDrawRule, unproject };
@@ -1,4 +1,4 @@
1
- import { Y as ControlMeasureId } from "../index-Ddt-obht.mjs";
1
+ import { X as ControlMeasureId } from "../index-DUGzYzPy.mjs";
2
2
  import { FeatureCollection, Geometry } from "geojson";
3
3
 
4
4
  //#region src/preview/index.d.ts
@@ -1,4 +1,4 @@
1
- import { a as DEFINITIONS, t as renderControlMeasure } from "../renderControlMeasure-CDCoQlZ-.mjs";
1
+ import { a as DEFINITIONS, t as renderControlMeasure } from "../renderControlMeasure-D5NKuws0.mjs";
2
2
  //#region src/preview/index.ts
3
3
  /**
4
4
  * Unitless `previewSample` points (~`[-1, 1]`) are scaled by this degree offset
@@ -849,19 +849,91 @@ const searchAreaDrawRule = {
849
849
  //#endregion
850
850
  //#region src/draw-rules/rectangle.ts
851
851
  /**
852
- * Axis-aligned rectangle: P1 and P2 are opposite corners. Both are user-clicked
853
- * and persisted; the generator derives the other two corners.
852
+ * Oriented rectangle: P1 and P2 are adjacent corners and define the first
853
+ * edge. P3 is the next corner, constrained to the perpendicular through P2.
854
+ * The generator derives the fourth corner.
854
855
  */
855
856
  function derive(points) {
856
- return clonePositions(points.slice(0, 2));
857
+ if (points.length < 2) return clonePositions(points);
858
+ const p1 = clonePosition(points[0]);
859
+ const p2 = clonePosition(points[1]);
860
+ if (points.length === 2) return [
861
+ p1,
862
+ p2,
863
+ clonePosition(p2)
864
+ ];
865
+ const frame = createBaselineFrame(p1, p2, {
866
+ origin: "p2",
867
+ normal: "right"
868
+ });
869
+ return [
870
+ p1,
871
+ p2,
872
+ frame?.pointAtNormalDistance(frame.signedNormalDistance(points[2])) ?? clonePosition(points[2])
873
+ ];
874
+ }
875
+ function guidePoints(points) {
876
+ const canonical = derive(points);
877
+ if (canonical.length < 3) return canonical;
878
+ const [c1, c2, c3] = canonical;
879
+ if (!c1 || !c2 || !c3) return canonical;
880
+ if (c2[0] === c3[0] && c2[1] === c3[1]) return [c1, c2];
881
+ const p1 = project(c1[0], c1[1]);
882
+ const p2 = project(c2[0], c2[1]);
883
+ const p4 = vecAdd(p1, vecSub(project(c3[0], c3[1]), p2));
884
+ return [
885
+ c1,
886
+ c2,
887
+ c3,
888
+ unproject(p4[0], p4[1]),
889
+ clonePosition(c1)
890
+ ];
891
+ }
892
+ function snapToAxis(point, origin, direction) {
893
+ const snapped = vecAdd(origin, vecScale(direction, vecDot(vecSub(project(point[0], point[1]), origin), direction)));
894
+ return unproject(snapped[0], snapped[1]);
857
895
  }
858
896
  const rectangleDrawRule = {
859
897
  id: "rectangle",
860
- minimumUserPoints: 2,
861
- canonicalPointCount: 2,
898
+ minimumUserPoints: 3,
899
+ minimumPreviewPoints: 2,
900
+ canonicalPointCount: 3,
901
+ showGuide: true,
902
+ guidePoints,
862
903
  derive,
863
904
  transform(event) {
864
- return derive(event.next);
905
+ const { previous, next, activePointIndex } = event;
906
+ if (previous.length < 3 || next.length < 3) return derive(next);
907
+ const frame = createBaselineFrame(previous[0], previous[1], {
908
+ origin: "p2",
909
+ normal: "right"
910
+ });
911
+ if (!frame) return derive(next);
912
+ if (activePointIndex === 0) return [
913
+ snapToAxis(next[0], frame.p2, frame.direction),
914
+ clonePosition(previous[1]),
915
+ clonePosition(previous[2])
916
+ ];
917
+ if (activePointIndex === 1) {
918
+ const p2 = snapToAxis(next[1], frame.p1, frame.direction);
919
+ const delta = vecSub(project(p2[0], p2[1]), frame.p2);
920
+ const projectedP3 = vecAdd(project(previous[2][0], previous[2][1]), delta);
921
+ const p3 = unproject(projectedP3[0], projectedP3[1]);
922
+ return [
923
+ clonePosition(previous[0]),
924
+ p2,
925
+ p3
926
+ ];
927
+ }
928
+ if (activePointIndex === 2) {
929
+ const p3 = frame.pointAtNormalDistance(frame.signedNormalDistance(next[2]));
930
+ if (p3) return [
931
+ clonePosition(previous[0]),
932
+ clonePosition(previous[1]),
933
+ p3
934
+ ];
935
+ }
936
+ return derive(next);
865
937
  }
866
938
  };
867
939
  //#endregion
@@ -2351,13 +2423,21 @@ function resolveEchelonHeight(echelonSize, echelonSizePixels, metersPerPixel) {
2351
2423
  if (echelonSizePixels !== void 0 && metersPerPixel !== void 0 && metersPerPixel > 0) h = echelonSizePixels * metersPerPixel;
2352
2424
  return Math.max(EPSILON, h);
2353
2425
  }
2426
+ /** Wraps `x` into `[0, 1)`, treating `x` as a fraction (matches the arc-length wrap below). */
2427
+ function wrap01(x) {
2428
+ return (x % 1 + 1) % 1;
2429
+ }
2354
2430
  /**
2355
2431
  * Places the Field B echelon glyph on the perimeter and computes its masking
2356
- * gap, anchored to the bottom edge and slid by `echelonPosition` (a signed
2357
- * fraction of the perimeter, wrapping at the seam). Returns empty geometry
2358
- * when the echelon resolves to none or the ring is degenerate.
2432
+ * gap, anchored by default to the bottom edge and slid by `echelonPosition`
2433
+ * (a signed fraction of the perimeter, wrapping at the seam). When
2434
+ * `echelonAnchor` is supplied, it replaces the bottom-edge anchor with an
2435
+ * absolute perimeter fraction (measured from the ring seam) — see
2436
+ * `BattlePositionOptions.echelonAnchor` for why (ADR-0023 rotate-freeze).
2437
+ * Returns empty geometry when the echelon resolves to none or the ring is
2438
+ * degenerate.
2359
2439
  */
2360
- function placeEchelon(perimeter, h, echelon, echelonPadding, echelonPosition) {
2440
+ function placeEchelon(perimeter, h, echelon, echelonPadding, echelonPosition, echelonAnchor) {
2361
2441
  const { segs, totalLength, anchorTarget } = perimeter;
2362
2442
  const spec = resolveEchelon(echelon);
2363
2443
  if (!spec || segs.length === 0 || totalLength < 1e-6) return {
@@ -2365,7 +2445,7 @@ function placeEchelon(perimeter, h, echelon, echelonPadding, echelonPosition) {
2365
2445
  fills: [],
2366
2446
  gaps: []
2367
2447
  };
2368
- const target = ((anchorTarget + echelonPosition * totalLength) % totalLength + totalLength) % totalLength;
2448
+ const target = (((echelonAnchor !== void 0 ? wrap01(echelonAnchor) * totalLength : anchorTarget) + echelonPosition * totalLength) % totalLength + totalLength) % totalLength;
2369
2449
  const { point, seg } = pointOnRing(segs, target);
2370
2450
  const { strokes, fills, width } = buildEchelonGlyph(point, seg.along, seg.perp, h, spec);
2371
2451
  const gaps = [];
@@ -2475,10 +2555,10 @@ const BATTLE_POSITION_METADATA = {
2475
2555
  * @param options - {@link BattlePositionOptions}.
2476
2556
  */
2477
2557
  function createBattlePosition(positions, options = {}) {
2478
- const { echelon = DEFAULT_BATTLE_POSITION_OPTIONS.echelon, echelonSize = DEFAULT_BATTLE_POSITION_OPTIONS.echelonSize, echelonSizePixels, echelonPadding = DEFAULT_BATTLE_POSITION_OPTIONS.echelonPadding, echelonPosition = DEFAULT_BATTLE_POSITION_OPTIONS.echelonPosition, metersPerPixel, smooth = DEFAULT_BATTLE_POSITION_OPTIONS.smooth, smoothResolution = DEFAULT_BATTLE_POSITION_OPTIONS.smoothResolution } = options;
2558
+ const { echelon = DEFAULT_BATTLE_POSITION_OPTIONS.echelon, echelonSize = DEFAULT_BATTLE_POSITION_OPTIONS.echelonSize, echelonSizePixels, echelonPadding = DEFAULT_BATTLE_POSITION_OPTIONS.echelonPadding, echelonPosition = DEFAULT_BATTLE_POSITION_OPTIONS.echelonPosition, echelonAnchor, metersPerPixel, smooth = DEFAULT_BATTLE_POSITION_OPTIONS.smooth, smoothResolution = DEFAULT_BATTLE_POSITION_OPTIONS.smoothResolution } = options;
2479
2559
  const h = resolveEchelonHeight(echelonSize, echelonSizePixels, metersPerPixel);
2480
2560
  const verts = buildClosedRing(positions, smooth, smoothResolution, DEFAULT_SMOOTH_RESOLUTION$6);
2481
- const { strokes, fills, gaps } = placeEchelon(buildAreaPerimeter(verts), h, echelon, echelonPadding, echelonPosition);
2561
+ const { strokes, fills, gaps } = placeEchelon(buildAreaPerimeter(verts), h, echelon, echelonPadding, echelonPosition, echelonAnchor);
2482
2562
  const boundaryCoords = buildGappedLine(verts, gaps);
2483
2563
  const features = [];
2484
2564
  if (boundaryCoords.length > 0) features.push({
@@ -2513,11 +2593,29 @@ function createBattlePosition(positions, options = {}) {
2513
2593
  features
2514
2594
  };
2515
2595
  }
2596
+ /**
2597
+ * `freezeOrientation` hook (ADR-0023) shared by Battle Position and Strong
2598
+ * Point: pins the echelon anchor to its current bottom-edge fraction so a
2599
+ * subsequent rigid rotation of `controlPoints` (e.g. the transform box's
2600
+ * rotate grip) does not re-derive a different "bottom edge" against the
2601
+ * rotated geometry. Returns `undefined` — nothing to freeze — when:
2602
+ * - `echelonAnchor` is already set (previously frozen or user-authored), or
2603
+ * - the echelon resolves to none (nothing visible to pin), or
2604
+ * - the ring is degenerate (no segments, or a near-zero perimeter).
2605
+ */
2606
+ function freezeEchelonAnchor(controlPoints, options) {
2607
+ if (options.echelonAnchor !== void 0) return void 0;
2608
+ if (!resolveEchelon(options.echelon ?? DEFAULT_BATTLE_POSITION_OPTIONS.echelon)) return void 0;
2609
+ const perimeter = buildAreaPerimeter(buildClosedRing(controlPoints, options.smooth ?? DEFAULT_BATTLE_POSITION_OPTIONS.smooth, options.smoothResolution ?? DEFAULT_BATTLE_POSITION_OPTIONS.smoothResolution, DEFAULT_SMOOTH_RESOLUTION$6));
2610
+ if (perimeter.segs.length === 0 || perimeter.totalLength < 1e-6) return void 0;
2611
+ return { echelonAnchor: perimeter.anchorTarget / perimeter.totalLength };
2612
+ }
2516
2613
  const BATTLE_POSITION = defineControlMeasure({
2517
2614
  metadata: BATTLE_POSITION_METADATA,
2518
2615
  generator: createBattlePosition,
2519
2616
  defaultOptions: DEFAULT_BATTLE_POSITION_OPTIONS,
2520
2617
  rule: area1DrawRule,
2618
+ freezeOrientation: freezeEchelonAnchor,
2521
2619
  previewSample: {
2522
2620
  controlPoints: [
2523
2621
  [-1, -.5],
@@ -4127,30 +4225,41 @@ const DEFAULT_GENERIC_RECTANGLE_OPTIONS = { filled: false };
4127
4225
  const GENERIC_RECTANGLE_METADATA = {
4128
4226
  id: "rectangle",
4129
4227
  name: "Rectangle",
4130
- description: "A non-doctrinal axis-aligned rectangle defined by two opposite corners.",
4228
+ description: "A non-doctrinal oriented rectangle defined by three adjacent corners.",
4131
4229
  entity: "Generic Graphics",
4132
4230
  entityType: "Basic Shape",
4133
4231
  entitySubtype: "Rectangle",
4134
4232
  value: "990103",
4135
- minCoordinates: 2,
4136
- maxCoordinates: 2,
4233
+ minCoordinates: 3,
4234
+ maxCoordinates: 3,
4137
4235
  geometry: "area",
4138
4236
  geometryTypes: ["Polygon"],
4139
4237
  drawRule: "Rectangle",
4140
4238
  params: FILLED_AREA_PARAMS
4141
4239
  };
4142
4240
  function createGenericRectangle(coordinates, options = {}) {
4143
- const p1 = project(coordinates[0][0], coordinates[0][1]);
4144
- const p2 = project(coordinates[1][0], coordinates[1][1]);
4145
- if (Math.abs(p2[0] - p1[0]) < 1e-6 || Math.abs(p2[1] - p1[1]) < 1e-6) return {
4241
+ const [c1, c2, c3] = rectangleDrawRule.derive(coordinates);
4242
+ if (!c1 || !c2 || !c3) return {
4243
+ type: "FeatureCollection",
4244
+ features: []
4245
+ };
4246
+ const p1 = project(c1[0], c1[1]);
4247
+ const p2 = project(c2[0], c2[1]);
4248
+ const p3 = project(c3[0], c3[1]);
4249
+ if (Math.hypot(p2[0] - p1[0], p2[1] - p1[1]) < 1e-6) return {
4250
+ type: "FeatureCollection",
4251
+ features: []
4252
+ };
4253
+ const fill = options.filled ?? DEFAULT_GENERIC_RECTANGLE_OPTIONS.filled;
4254
+ if (Math.hypot(p3[0] - p2[0], p3[1] - p2[1]) < 1e-6) return {
4146
4255
  type: "FeatureCollection",
4147
4256
  features: []
4148
4257
  };
4149
4258
  const ring = [
4150
4259
  p1,
4151
- [p2[0], p1[1]],
4152
4260
  p2,
4153
- [p1[0], p2[1]],
4261
+ p3,
4262
+ [p1[0] + p3[0] - p2[0], p1[1] + p3[1] - p2[1]],
4154
4263
  p1
4155
4264
  ].map((point) => unproject(point[0], point[1]));
4156
4265
  return {
@@ -4159,7 +4268,7 @@ function createGenericRectangle(coordinates, options = {}) {
4159
4268
  type: "Feature",
4160
4269
  properties: {
4161
4270
  part: "rectangle",
4162
- fill: options.filled ?? DEFAULT_GENERIC_RECTANGLE_OPTIONS.filled
4271
+ fill
4163
4272
  },
4164
4273
  geometry: {
4165
4274
  type: "Polygon",
@@ -4173,7 +4282,11 @@ const GENERIC_RECTANGLE = defineControlMeasure({
4173
4282
  generator: createGenericRectangle,
4174
4283
  defaultOptions: DEFAULT_GENERIC_RECTANGLE_OPTIONS,
4175
4284
  rule: rectangleDrawRule,
4176
- previewSample: { controlPoints: [[-.9, -.55], [.9, .55]] }
4285
+ previewSample: { controlPoints: [
4286
+ [-.9, -.55],
4287
+ [.9, -.55],
4288
+ [.9, .55]
4289
+ ] }
4177
4290
  });
4178
4291
  //#endregion
4179
4292
  //#region src/generators/cm34-mission-tasks/clear.ts
@@ -6519,11 +6632,11 @@ function buildStrongPointTics(perimeter, gaps, h) {
6519
6632
  * @param options - {@link StrongPointOptions}.
6520
6633
  */
6521
6634
  function createStrongPoint(positions, options = {}) {
6522
- const { echelon = DEFAULT_STRONG_POINT_OPTIONS.echelon, echelonSize = DEFAULT_STRONG_POINT_OPTIONS.echelonSize, echelonSizePixels, echelonPadding = DEFAULT_STRONG_POINT_OPTIONS.echelonPadding, echelonPosition = DEFAULT_STRONG_POINT_OPTIONS.echelonPosition, metersPerPixel, smooth = DEFAULT_STRONG_POINT_OPTIONS.smooth, smoothResolution = DEFAULT_STRONG_POINT_OPTIONS.smoothResolution } = options;
6635
+ const { echelon = DEFAULT_STRONG_POINT_OPTIONS.echelon, echelonSize = DEFAULT_STRONG_POINT_OPTIONS.echelonSize, echelonSizePixels, echelonPadding = DEFAULT_STRONG_POINT_OPTIONS.echelonPadding, echelonPosition = DEFAULT_STRONG_POINT_OPTIONS.echelonPosition, echelonAnchor, metersPerPixel, smooth = DEFAULT_STRONG_POINT_OPTIONS.smooth, smoothResolution = DEFAULT_STRONG_POINT_OPTIONS.smoothResolution } = options;
6523
6636
  const h = resolveEchelonHeight(echelonSize, echelonSizePixels, metersPerPixel);
6524
6637
  const verts = buildClosedRing(positions, smooth, smoothResolution, DEFAULT_SMOOTH_RESOLUTION);
6525
6638
  const perimeter = buildAreaPerimeter(verts);
6526
- const { strokes, fills, gaps } = placeEchelon(perimeter, h, echelon, echelonPadding, echelonPosition);
6639
+ const { strokes, fills, gaps } = placeEchelon(perimeter, h, echelon, echelonPadding, echelonPosition, echelonAnchor);
6527
6640
  const boundaryCoords = buildGappedLine(verts, gaps);
6528
6641
  const tics = buildStrongPointTics(perimeter, gaps, h);
6529
6642
  const features = [];
@@ -6572,6 +6685,7 @@ const STRONG_POINT = defineControlMeasure({
6572
6685
  generator: createStrongPoint,
6573
6686
  defaultOptions: DEFAULT_STRONG_POINT_OPTIONS,
6574
6687
  rule: area1DrawRule,
6688
+ freezeOrientation: freezeEchelonAnchor,
6575
6689
  previewSample: {
6576
6690
  controlPoints: [
6577
6691
  [-1, -.5],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orbat-mapper/control-measures",
3
- "version": "0.2.0-alpha.5",
3
+ "version": "0.2.0-alpha.6",
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",