@orbat-mapper/control-measures 0.2.0-alpha.5 → 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.
@@ -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-DGWf44sn.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-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. Assuming they cross as per design.
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 ptNeck = spine[spine.length - 1];
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 headHalfWidth = pointToInfiniteLineDistance(ptWidth, ptNeck, ptTip);
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 innerTip = vecAdd(ptBase, vecScale(tipDir, Math.min(notchDepth, headLength - EPSILON)));
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 = [...spine, shaftEndCenter];
274
+ const fullSpine = [...remainingSpine, shaftEndCenter];
249
275
  return {
250
276
  shaftLeft: offsetPolyline(fullSpine, shaftHalfWidth, roundedBends, bendSegments),
251
277
  shaftRight: offsetPolyline(fullSpine, -shaftHalfWidth, roundedBends, bendSegments),
@@ -849,19 +875,91 @@ const searchAreaDrawRule = {
849
875
  //#endregion
850
876
  //#region src/draw-rules/rectangle.ts
851
877
  /**
852
- * Axis-aligned rectangle: P1 and P2 are opposite corners. Both are user-clicked
853
- * and persisted; the generator derives the other two corners.
878
+ * Oriented rectangle: P1 and P2 are adjacent corners and define the first
879
+ * edge. P3 is the next corner, constrained to the perpendicular through P2.
880
+ * The generator derives the fourth corner.
854
881
  */
855
882
  function derive(points) {
856
- return clonePositions(points.slice(0, 2));
883
+ if (points.length < 2) return clonePositions(points);
884
+ const p1 = clonePosition(points[0]);
885
+ const p2 = clonePosition(points[1]);
886
+ if (points.length === 2) return [
887
+ p1,
888
+ p2,
889
+ clonePosition(p2)
890
+ ];
891
+ const frame = createBaselineFrame(p1, p2, {
892
+ origin: "p2",
893
+ normal: "right"
894
+ });
895
+ return [
896
+ p1,
897
+ p2,
898
+ frame?.pointAtNormalDistance(frame.signedNormalDistance(points[2])) ?? clonePosition(points[2])
899
+ ];
900
+ }
901
+ function guidePoints(points) {
902
+ const canonical = derive(points);
903
+ if (canonical.length < 3) return canonical;
904
+ const [c1, c2, c3] = canonical;
905
+ if (!c1 || !c2 || !c3) return canonical;
906
+ if (c2[0] === c3[0] && c2[1] === c3[1]) return [c1, c2];
907
+ const p1 = project(c1[0], c1[1]);
908
+ const p2 = project(c2[0], c2[1]);
909
+ const p4 = vecAdd(p1, vecSub(project(c3[0], c3[1]), p2));
910
+ return [
911
+ c1,
912
+ c2,
913
+ c3,
914
+ unproject(p4[0], p4[1]),
915
+ clonePosition(c1)
916
+ ];
917
+ }
918
+ function snapToAxis(point, origin, direction) {
919
+ const snapped = vecAdd(origin, vecScale(direction, vecDot(vecSub(project(point[0], point[1]), origin), direction)));
920
+ return unproject(snapped[0], snapped[1]);
857
921
  }
858
922
  const rectangleDrawRule = {
859
923
  id: "rectangle",
860
- minimumUserPoints: 2,
861
- canonicalPointCount: 2,
924
+ minimumUserPoints: 3,
925
+ minimumPreviewPoints: 2,
926
+ canonicalPointCount: 3,
927
+ showGuide: true,
928
+ guidePoints,
862
929
  derive,
863
930
  transform(event) {
864
- return derive(event.next);
931
+ const { previous, next, activePointIndex } = event;
932
+ if (previous.length < 3 || next.length < 3) return derive(next);
933
+ const frame = createBaselineFrame(previous[0], previous[1], {
934
+ origin: "p2",
935
+ normal: "right"
936
+ });
937
+ if (!frame) return derive(next);
938
+ if (activePointIndex === 0) return [
939
+ snapToAxis(next[0], frame.p2, frame.direction),
940
+ clonePosition(previous[1]),
941
+ clonePosition(previous[2])
942
+ ];
943
+ if (activePointIndex === 1) {
944
+ const p2 = snapToAxis(next[1], frame.p1, frame.direction);
945
+ const delta = vecSub(project(p2[0], p2[1]), frame.p2);
946
+ const projectedP3 = vecAdd(project(previous[2][0], previous[2][1]), delta);
947
+ const p3 = unproject(projectedP3[0], projectedP3[1]);
948
+ return [
949
+ clonePosition(previous[0]),
950
+ p2,
951
+ p3
952
+ ];
953
+ }
954
+ if (activePointIndex === 2) {
955
+ const p3 = frame.pointAtNormalDistance(frame.signedNormalDistance(next[2]));
956
+ if (p3) return [
957
+ clonePosition(previous[0]),
958
+ clonePosition(previous[1]),
959
+ p3
960
+ ];
961
+ }
962
+ return derive(next);
865
963
  }
866
964
  };
867
965
  //#endregion
@@ -1754,7 +1852,7 @@ function createAttackHelicopter(coordinates, options = {}) {
1754
1852
  type: "FeatureCollection",
1755
1853
  features: []
1756
1854
  };
1757
- const center = lineIntersection(pL, pIR, pR, pIL);
1855
+ const center = lineIntersection(pL, pIR, pR, pIL) ?? geometry.ptBase;
1758
1856
  const features = [{
1759
1857
  type: "Feature",
1760
1858
  properties: {},
@@ -2266,15 +2364,18 @@ function closedCatmullRom(points, samples) {
2266
2364
  }
2267
2365
  //#endregion
2268
2366
  //#region src/internal/area-echelon.ts
2269
- /** Mean of the ring's distinct vertices, used as the outward-normal reference. */
2270
- function ringCentroid(verts, count) {
2271
- let cx = 0;
2272
- let cy = 0;
2273
- for (let i = 0; i < count; i++) {
2274
- cx += verts[i][0];
2275
- cy += verts[i][1];
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];
2276
2377
  }
2277
- return [cx / count, cy / count];
2378
+ return area2;
2278
2379
  }
2279
2380
  /**
2280
2381
  * Projects `positions` and returns a closed ring (first == last), optionally
@@ -2294,7 +2395,7 @@ function buildClosedRing(positions, smooth, smoothResolution, defaultSmoothResol
2294
2395
  * projected y), the side opposite the front.
2295
2396
  */
2296
2397
  function buildAreaPerimeter(verts) {
2297
- const centroid = ringCentroid(verts, verts.length - 1);
2398
+ const ccw = ringSignedArea2(verts) > 0;
2298
2399
  const segs = [];
2299
2400
  let totalLength = 0;
2300
2401
  let anchorTarget = 0;
@@ -2307,8 +2408,7 @@ function buildAreaPerimeter(verts) {
2307
2408
  if (length < 1e-6) continue;
2308
2409
  const along = vecNorm(edge);
2309
2410
  const mid = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2];
2310
- let perp = [-along[1], along[0]];
2311
- 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]];
2312
2412
  segs.push({
2313
2413
  start: a,
2314
2414
  along,
@@ -2351,13 +2451,21 @@ function resolveEchelonHeight(echelonSize, echelonSizePixels, metersPerPixel) {
2351
2451
  if (echelonSizePixels !== void 0 && metersPerPixel !== void 0 && metersPerPixel > 0) h = echelonSizePixels * metersPerPixel;
2352
2452
  return Math.max(EPSILON, h);
2353
2453
  }
2454
+ /** Wraps `x` into `[0, 1)`, treating `x` as a fraction (matches the arc-length wrap below). */
2455
+ function wrap01(x) {
2456
+ return (x % 1 + 1) % 1;
2457
+ }
2354
2458
  /**
2355
2459
  * 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.
2460
+ * gap, anchored by default to the bottom edge and slid by `echelonPosition`
2461
+ * (a signed fraction of the perimeter, wrapping at the seam). When
2462
+ * `echelonAnchor` is supplied, it replaces the bottom-edge anchor with an
2463
+ * absolute perimeter fraction (measured from the ring seam) — see
2464
+ * `BattlePositionOptions.echelonAnchor` for why (ADR-0023 rotate-freeze).
2465
+ * Returns empty geometry when the echelon resolves to none or the ring is
2466
+ * degenerate.
2359
2467
  */
2360
- function placeEchelon(perimeter, h, echelon, echelonPadding, echelonPosition) {
2468
+ function placeEchelon(perimeter, h, echelon, echelonPadding, echelonPosition, echelonAnchor) {
2361
2469
  const { segs, totalLength, anchorTarget } = perimeter;
2362
2470
  const spec = resolveEchelon(echelon);
2363
2471
  if (!spec || segs.length === 0 || totalLength < 1e-6) return {
@@ -2365,7 +2473,7 @@ function placeEchelon(perimeter, h, echelon, echelonPadding, echelonPosition) {
2365
2473
  fills: [],
2366
2474
  gaps: []
2367
2475
  };
2368
- const target = ((anchorTarget + echelonPosition * totalLength) % totalLength + totalLength) % totalLength;
2476
+ const target = (((echelonAnchor !== void 0 ? wrap01(echelonAnchor) * totalLength : anchorTarget) + echelonPosition * totalLength) % totalLength + totalLength) % totalLength;
2369
2477
  const { point, seg } = pointOnRing(segs, target);
2370
2478
  const { strokes, fills, width } = buildEchelonGlyph(point, seg.along, seg.perp, h, spec);
2371
2479
  const gaps = [];
@@ -2475,10 +2583,10 @@ const BATTLE_POSITION_METADATA = {
2475
2583
  * @param options - {@link BattlePositionOptions}.
2476
2584
  */
2477
2585
  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;
2586
+ 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
2587
  const h = resolveEchelonHeight(echelonSize, echelonSizePixels, metersPerPixel);
2480
2588
  const verts = buildClosedRing(positions, smooth, smoothResolution, DEFAULT_SMOOTH_RESOLUTION$6);
2481
- const { strokes, fills, gaps } = placeEchelon(buildAreaPerimeter(verts), h, echelon, echelonPadding, echelonPosition);
2589
+ const { strokes, fills, gaps } = placeEchelon(buildAreaPerimeter(verts), h, echelon, echelonPadding, echelonPosition, echelonAnchor);
2482
2590
  const boundaryCoords = buildGappedLine(verts, gaps);
2483
2591
  const features = [];
2484
2592
  if (boundaryCoords.length > 0) features.push({
@@ -2513,11 +2621,29 @@ function createBattlePosition(positions, options = {}) {
2513
2621
  features
2514
2622
  };
2515
2623
  }
2624
+ /**
2625
+ * `freezeOrientation` hook (ADR-0023) shared by Battle Position and Strong
2626
+ * Point: pins the echelon anchor to its current bottom-edge fraction so a
2627
+ * subsequent rigid rotation of `controlPoints` (e.g. the transform box's
2628
+ * rotate grip) does not re-derive a different "bottom edge" against the
2629
+ * rotated geometry. Returns `undefined` — nothing to freeze — when:
2630
+ * - `echelonAnchor` is already set (previously frozen or user-authored), or
2631
+ * - the echelon resolves to none (nothing visible to pin), or
2632
+ * - the ring is degenerate (no segments, or a near-zero perimeter).
2633
+ */
2634
+ function freezeEchelonAnchor(controlPoints, options) {
2635
+ if (options.echelonAnchor !== void 0) return void 0;
2636
+ if (!resolveEchelon(options.echelon ?? DEFAULT_BATTLE_POSITION_OPTIONS.echelon)) return void 0;
2637
+ const perimeter = buildAreaPerimeter(buildClosedRing(controlPoints, options.smooth ?? DEFAULT_BATTLE_POSITION_OPTIONS.smooth, options.smoothResolution ?? DEFAULT_BATTLE_POSITION_OPTIONS.smoothResolution, DEFAULT_SMOOTH_RESOLUTION$6));
2638
+ if (perimeter.segs.length === 0 || perimeter.totalLength < 1e-6) return void 0;
2639
+ return { echelonAnchor: perimeter.anchorTarget / perimeter.totalLength };
2640
+ }
2516
2641
  const BATTLE_POSITION = defineControlMeasure({
2517
2642
  metadata: BATTLE_POSITION_METADATA,
2518
2643
  generator: createBattlePosition,
2519
2644
  defaultOptions: DEFAULT_BATTLE_POSITION_OPTIONS,
2520
2645
  rule: area1DrawRule,
2646
+ freezeOrientation: freezeEchelonAnchor,
2521
2647
  previewSample: {
2522
2648
  controlPoints: [
2523
2649
  [-1, -.5],
@@ -4127,30 +4253,41 @@ const DEFAULT_GENERIC_RECTANGLE_OPTIONS = { filled: false };
4127
4253
  const GENERIC_RECTANGLE_METADATA = {
4128
4254
  id: "rectangle",
4129
4255
  name: "Rectangle",
4130
- description: "A non-doctrinal axis-aligned rectangle defined by two opposite corners.",
4256
+ description: "A non-doctrinal oriented rectangle defined by three adjacent corners.",
4131
4257
  entity: "Generic Graphics",
4132
4258
  entityType: "Basic Shape",
4133
4259
  entitySubtype: "Rectangle",
4134
4260
  value: "990103",
4135
- minCoordinates: 2,
4136
- maxCoordinates: 2,
4261
+ minCoordinates: 3,
4262
+ maxCoordinates: 3,
4137
4263
  geometry: "area",
4138
4264
  geometryTypes: ["Polygon"],
4139
4265
  drawRule: "Rectangle",
4140
4266
  params: FILLED_AREA_PARAMS
4141
4267
  };
4142
4268
  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 {
4269
+ const [c1, c2, c3] = rectangleDrawRule.derive(coordinates);
4270
+ if (!c1 || !c2 || !c3) return {
4271
+ type: "FeatureCollection",
4272
+ features: []
4273
+ };
4274
+ const p1 = project(c1[0], c1[1]);
4275
+ const p2 = project(c2[0], c2[1]);
4276
+ const p3 = project(c3[0], c3[1]);
4277
+ if (Math.hypot(p2[0] - p1[0], p2[1] - p1[1]) < 1e-6) return {
4278
+ type: "FeatureCollection",
4279
+ features: []
4280
+ };
4281
+ const fill = options.filled ?? DEFAULT_GENERIC_RECTANGLE_OPTIONS.filled;
4282
+ if (Math.hypot(p3[0] - p2[0], p3[1] - p2[1]) < 1e-6) return {
4146
4283
  type: "FeatureCollection",
4147
4284
  features: []
4148
4285
  };
4149
4286
  const ring = [
4150
4287
  p1,
4151
- [p2[0], p1[1]],
4152
4288
  p2,
4153
- [p1[0], p2[1]],
4289
+ p3,
4290
+ [p1[0] + p3[0] - p2[0], p1[1] + p3[1] - p2[1]],
4154
4291
  p1
4155
4292
  ].map((point) => unproject(point[0], point[1]));
4156
4293
  return {
@@ -4159,7 +4296,7 @@ function createGenericRectangle(coordinates, options = {}) {
4159
4296
  type: "Feature",
4160
4297
  properties: {
4161
4298
  part: "rectangle",
4162
- fill: options.filled ?? DEFAULT_GENERIC_RECTANGLE_OPTIONS.filled
4299
+ fill
4163
4300
  },
4164
4301
  geometry: {
4165
4302
  type: "Polygon",
@@ -4173,7 +4310,11 @@ const GENERIC_RECTANGLE = defineControlMeasure({
4173
4310
  generator: createGenericRectangle,
4174
4311
  defaultOptions: DEFAULT_GENERIC_RECTANGLE_OPTIONS,
4175
4312
  rule: rectangleDrawRule,
4176
- previewSample: { controlPoints: [[-.9, -.55], [.9, .55]] }
4313
+ previewSample: { controlPoints: [
4314
+ [-.9, -.55],
4315
+ [.9, -.55],
4316
+ [.9, .55]
4317
+ ] }
4177
4318
  });
4178
4319
  //#endregion
4179
4320
  //#region src/generators/cm34-mission-tasks/clear.ts
@@ -6519,11 +6660,11 @@ function buildStrongPointTics(perimeter, gaps, h) {
6519
6660
  * @param options - {@link StrongPointOptions}.
6520
6661
  */
6521
6662
  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;
6663
+ 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
6664
  const h = resolveEchelonHeight(echelonSize, echelonSizePixels, metersPerPixel);
6524
6665
  const verts = buildClosedRing(positions, smooth, smoothResolution, DEFAULT_SMOOTH_RESOLUTION);
6525
6666
  const perimeter = buildAreaPerimeter(verts);
6526
- const { strokes, fills, gaps } = placeEchelon(perimeter, h, echelon, echelonPadding, echelonPosition);
6667
+ const { strokes, fills, gaps } = placeEchelon(perimeter, h, echelon, echelonPadding, echelonPosition, echelonAnchor);
6527
6668
  const boundaryCoords = buildGappedLine(verts, gaps);
6528
6669
  const tics = buildStrongPointTics(perimeter, gaps, h);
6529
6670
  const features = [];
@@ -6572,6 +6713,7 @@ const STRONG_POINT = defineControlMeasure({
6572
6713
  generator: createStrongPoint,
6573
6714
  defaultOptions: DEFAULT_STRONG_POINT_OPTIONS,
6574
6715
  rule: area1DrawRule,
6716
+ freezeOrientation: freezeEchelonAnchor,
6575
6717
  previewSample: {
6576
6718
  controlPoints: [
6577
6719
  [-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.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",