@orbat-mapper/control-measures 0.2.0-alpha.29 → 0.2.0-alpha.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index-J_5z80SV.d.mts → index-DmAFButD.d.mts} +3 -3
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/preview/index.d.mts +1 -1
- package/dist/preview/index.mjs +1 -1
- package/dist/{renderControlMeasure-BdbObD8B.mjs → renderControlMeasure-CzhJJJHO.mjs} +253 -182
- package/package.json +1 -1
|
@@ -951,7 +951,7 @@ interface DirectionOfAttackAviationOptions extends LabelSizeOptions, SmoothLineO
|
|
|
951
951
|
}
|
|
952
952
|
declare const DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS: DirectionOfAttackAviationOptions;
|
|
953
953
|
/** Builds the route, aviation bow-tie, arrowhead, and optional T/W/W1 labels. */
|
|
954
|
-
declare function createDirectionOfAttackAviation(coordinates: Position[], options?: DirectionOfAttackAviationOptions, textAmplifiers?: CanonicalTextAmplifiers): FeatureCollection<MultiLineString | Point>;
|
|
954
|
+
declare function createDirectionOfAttackAviation(coordinates: Position[], options?: DirectionOfAttackAviationOptions, textAmplifiers?: CanonicalTextAmplifiers, context?: ControlMeasureGeneratorContext): FeatureCollection<MultiLineString | Point>;
|
|
955
955
|
//#endregion
|
|
956
956
|
//#region src/generators/cm14-maneuver-lines/direction-of-attack-shared.d.ts
|
|
957
957
|
interface DirectionOfAttackLineOptions extends LabelSizeOptions, SmoothLineOptions {
|
|
@@ -968,12 +968,12 @@ interface DirectionOfMainAttackOptions extends DirectionOfAttackLineOptions {
|
|
|
968
968
|
arrowheadOutlineRatio?: number;
|
|
969
969
|
}
|
|
970
970
|
declare const DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS: DirectionOfMainAttackOptions;
|
|
971
|
-
declare function createDirectionOfMainAttack(coordinates: Position[], options?: DirectionOfMainAttackOptions, textAmplifiers?: CanonicalTextAmplifiers): FeatureCollection<MultiLineString | Point>;
|
|
971
|
+
declare function createDirectionOfMainAttack(coordinates: Position[], options?: DirectionOfMainAttackOptions, textAmplifiers?: CanonicalTextAmplifiers, context?: ControlMeasureGeneratorContext): FeatureCollection<MultiLineString | Point>;
|
|
972
972
|
//#endregion
|
|
973
973
|
//#region src/generators/cm14-maneuver-lines/direction-of-supporting-attack.d.ts
|
|
974
974
|
type DirectionOfSupportingAttackOptions = DirectionOfAttackLineOptions;
|
|
975
975
|
declare const DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS: DirectionOfSupportingAttackOptions;
|
|
976
|
-
declare function createDirectionOfSupportingAttack(coordinates: Position[], options?: DirectionOfSupportingAttackOptions, textAmplifiers?: CanonicalTextAmplifiers): FeatureCollection<MultiLineString | Point>;
|
|
976
|
+
declare function createDirectionOfSupportingAttack(coordinates: Position[], options?: DirectionOfSupportingAttackOptions, textAmplifiers?: CanonicalTextAmplifiers, context?: ControlMeasureGeneratorContext): FeatureCollection<MultiLineString | Point>;
|
|
977
977
|
//#endregion
|
|
978
978
|
//#region src/generators/cm14-maneuver-lines/principalDirectionOfFire.d.ts
|
|
979
979
|
/**
|
package/dist/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { $ as DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, $n as DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS, $t as DEFAULT_SUPPORT_BY_FIRE_OPTIONS, A as roundToFixed, An as PickupZoneOptions, Ar as CanonicalTextAmplifiers, At as DEFAULT_COVER_OPTIONS, B as cloneControlMeasure, Bn as EncirclementOptions, Br as AnchorTransformEvent, Bt as DEFAULT_BREACH_OPTIONS, C as BaselineFrame, Cn as DEFAULT_MAIN_ATTACK_OPTIONS, Cr as ControlMeasureGeometryType, Ct as DEFAULT_SCREEN_OPTIONS, D as createBaselineFrame, Dn as AreaOfOperationsOptions, Dr as TextAmplifierDescriptor, Dt as DEFAULT_DELAY_OPTIONS, E as BaselineFrameOrigin, En as computeInitialWidthPoint, Er as ParamDescriptor, Et as GuardOptions, F as applyBoxTransformOptions, Fn as AssemblyAreaOptions, Fr as TextAmplifierKey, Ft as CanalizeOptions, G as ControlMeasureKind, Gn as StyleHints, Gt as DEFAULT_HANDOVER_LINE_OPTIONS, H as CONTROL_MEASURE_IDS, Hn as FinalProtectiveFireOptions, Ht as DEFAULT_BLOCK_MISSION_TASK_OPTIONS, I as freezeOrientationOptions, In as DEFAULT_ASSEMBLY_AREA_OPTIONS, Ir as TextAmplifiers, It as DEFAULT_CANALIZE_OPTIONS, J as getControlMeasureMetadataByValue, Jn as PrincipalDirectionOfFireOptions, Jt as PhaseLineOptions, K as OptionsByKind, Kn as controlMeasureIdFromFeature, Kt as HandoverLineOptions, L as RenderOptions, Ln as AreaDefenseOptions, Lr as canonicalTextAmplifierKey, Lt as BypassOptions, M as SimpleStyleRender, Mn as LandingZoneOptions, Mr as LabelPlacementOverride, Mt as TacticalArrowOptions, N as toSimpleStyle, Nn as DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS, Nr as TEXT_AMPLIFIER_FIELDS, Nt as ClearOptions, O as EPSILON, On as DEFAULT_AREA_OF_OPERATIONS_OPTIONS, Or as AmplifierPlacement, Ot as DelayOptions, P as resolveStyleHints, Pn as JointTacticalActionAreaOptions, Pr as TextAmplifierField, Pt as DEFAULT_CLEAR_OPTIONS, Q as ObstacleBypassImpossibleOptions, Qn as DirectionOfMainAttackOptions, Qt as DEFAULT_ATTACK_BY_FIRE_OPTIONS, R as renderControlMeasure, Rn as DEFAULT_AREA_DEFENSE_OPTIONS, Rr as normalizeTextAmplifiers, Rt as DEFAULT_BYPASS_OPTIONS, S as snapToMidpointPerpendicular, Sn as SupportingAttackOptions, Sr as ControlMeasureGeometry, St as DEFAULT_ANTITANK_DITCH_OPTIONS, T as BaselineFrameOptions, Tn as calculateMetrics, Tr as ControlMeasurePaintCapability, Tt as DEFAULT_GUARD_OPTIONS, U as CONTROL_MEASURE_METADATA, Un as ControlMeasureRender, Ut as BattleHandoverLineOptions, V as isKind, Vn as DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, Vr as ControlMeasureDrawRule, Vt as BlockMissionTaskOptions, W as ControlMeasureId, Wn as FeaturePartProps, Wt as DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS, X as listControlMeasureMetadata, Xn as DirectionOfSupportingAttackOptions, Xt as FLOTOptions, Y as getDefaultOptions, Yn as DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS, Yt as DEFAULT_FLOT_OPTIONS, Z as DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, Zn as DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS, Zt as AttackByFireOptions, _ as MidpointPerpendicularDrawRuleOptions, _n as DEFAULT_BLOCK_ARROW_OPTIONS, _r as unproject, _t as DEFAULT_FORTIFIED_LINE_OPTIONS, a as supportByFireDrawRule, an as DEFAULT_GENERIC_TEXT_OPTIONS, ar as ControlMeasureStyle, at as DEFAULT_FIX_OPTIONS, b as getMidpointPerpendicularSignedDistance, bn as DEFAULT_CLASSIC_ARROW_OPTIONS, br as BoxTransformDelta, bt as DEFAULT_ANTITANK_WALL_OPTIONS, c as line23DrawRule, cn as GenericCircleOptions, cr as GenericC2LineOptions, ct as DisruptOptions, d as ambushDrawRule, dn as DEFAULT_GENERIC_POLYGON_OPTIONS, dr as DEFAULT_LIGHT_LINE_OPTIONS, dt as DEFAULT_TURNING_MOVEMENT_OPTIONS, en as SupportByFireOptions, er as DirectionOfAttackAviationOptions, et as ObstacleBypassDifficultOptions, f as attackByFireDrawRule, fn as GenericPolygonOptions, fr as LightLineOptions, ft as TurningMovementOptions, g as blockDrawRule, gn as BlockArrowOptions, gr as project, gt as FortifiedAreaOptions, h as disruptDrawRule, hn as BlockArrowHeadStyle, hr as haversineDistance, ht as DEFAULT_FORTIFIED_AREA_OPTIONS, i as axis1DrawRule, in as DEFAULT_AIRBORNE_ATTACK_OPTIONS, ir as DEFAULT_BATTLE_POSITION_OPTIONS, it as TurnOptions, j as SimpleStyleProps, jn as DEFAULT_LANDING_ZONE_OPTIONS, jr as GeneratedLabelKey, jt as DEFAULT_TACTICAL_ARROW_OPTIONS, k as getMetersPerPixel, kn as DEFAULT_PICKUP_ZONE_OPTIONS, kr as AmplifierPlacements, kt as CoverOptions, l as turnDrawRule, ln as DEFAULT_GENERIC_RECTANGLE_OPTIONS, lr as DEFAULT_ENGINEER_WORK_LINE_OPTIONS, lt as BlockOptions, m as centerRadiusDrawRule, mn as GenericLineOptions, mr as Point2D, mt as FrontalAttackOptions, n as DEFAULT_AMBUSH_OPTIONS, nn as DEFAULT_ATTACK_HELICOPTER_OPTIONS, nr as StrongPointOptions, nt as ObstacleBypassEasyOptions, o as line26DrawRule, on as GenericTextOptions, or as FillPattern, ot as FixOptions, p as point12DrawRule, pn as DEFAULT_GENERIC_LINE_OPTIONS, pr as LabelSizeOptions, pt as DEFAULT_FRONTAL_ATTACK_OPTIONS, q as getControlMeasureMetadata, qn as DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, qt as DEFAULT_PHASE_LINE_OPTIONS, r as rectangleDrawRule, rn as AirborneAttackOptions, rr as BattlePositionOptions, rt as DEFAULT_TURN_OPTIONS, s as line24DrawRule, sn as DEFAULT_GENERIC_CIRCLE_OPTIONS, sr as DEFAULT_GENERIC_C2_LINE_OPTIONS, st as DEFAULT_DISRUPT_OPTIONS, t as AmbushOptions, tn as AttackHelicopterOptions, tr as DEFAULT_STRONG_POINT_OPTIONS, tt as DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, u as line1DrawRule, un as GenericRectangleOptions, ur as EngineerWorkLineOptions, ut as DEFAULT_BLOCK_OPTIONS, v as computeDefaultMidpointPerpendicularPoint, vn as ClassicArrowHeadStyle, vr as BoundaryOptions, vt as FortifiedLineOptions, w as BaselineFrameNormal, wn as MainAttackOptions, wr as ControlMeasureMetadata, wt as ScreenOptions, x as pointOnMidpointPerpendicularAxis, xn as DEFAULT_SUPPORTING_ATTACK_OPTIONS, xr as ControlMeasureFillCapability, xt as AntitankDitchOptions, y as createMidpointPerpendicularDrawRule, yn as ClassicArrowOptions, yr as DEFAULT_BOUNDARY_OPTIONS, yt as AntitankWallOptions, z as ControlMeasure, zn as DEFAULT_ENCIRCLEMENT_OPTIONS, zr as resolveAmplifierPlacement, zt as BreachOptions } from "./index-
|
|
1
|
+
import { $ as DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, $n as DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS, $t as DEFAULT_SUPPORT_BY_FIRE_OPTIONS, A as roundToFixed, An as PickupZoneOptions, Ar as CanonicalTextAmplifiers, At as DEFAULT_COVER_OPTIONS, B as cloneControlMeasure, Bn as EncirclementOptions, Br as AnchorTransformEvent, Bt as DEFAULT_BREACH_OPTIONS, C as BaselineFrame, Cn as DEFAULT_MAIN_ATTACK_OPTIONS, Cr as ControlMeasureGeometryType, Ct as DEFAULT_SCREEN_OPTIONS, D as createBaselineFrame, Dn as AreaOfOperationsOptions, Dr as TextAmplifierDescriptor, Dt as DEFAULT_DELAY_OPTIONS, E as BaselineFrameOrigin, En as computeInitialWidthPoint, Er as ParamDescriptor, Et as GuardOptions, F as applyBoxTransformOptions, Fn as AssemblyAreaOptions, Fr as TextAmplifierKey, Ft as CanalizeOptions, G as ControlMeasureKind, Gn as StyleHints, Gt as DEFAULT_HANDOVER_LINE_OPTIONS, H as CONTROL_MEASURE_IDS, Hn as FinalProtectiveFireOptions, Ht as DEFAULT_BLOCK_MISSION_TASK_OPTIONS, I as freezeOrientationOptions, In as DEFAULT_ASSEMBLY_AREA_OPTIONS, Ir as TextAmplifiers, It as DEFAULT_CANALIZE_OPTIONS, J as getControlMeasureMetadataByValue, Jn as PrincipalDirectionOfFireOptions, Jt as PhaseLineOptions, K as OptionsByKind, Kn as controlMeasureIdFromFeature, Kt as HandoverLineOptions, L as RenderOptions, Ln as AreaDefenseOptions, Lr as canonicalTextAmplifierKey, Lt as BypassOptions, M as SimpleStyleRender, Mn as LandingZoneOptions, Mr as LabelPlacementOverride, Mt as TacticalArrowOptions, N as toSimpleStyle, Nn as DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS, Nr as TEXT_AMPLIFIER_FIELDS, Nt as ClearOptions, O as EPSILON, On as DEFAULT_AREA_OF_OPERATIONS_OPTIONS, Or as AmplifierPlacement, Ot as DelayOptions, P as resolveStyleHints, Pn as JointTacticalActionAreaOptions, Pr as TextAmplifierField, Pt as DEFAULT_CLEAR_OPTIONS, Q as ObstacleBypassImpossibleOptions, Qn as DirectionOfMainAttackOptions, Qt as DEFAULT_ATTACK_BY_FIRE_OPTIONS, R as renderControlMeasure, Rn as DEFAULT_AREA_DEFENSE_OPTIONS, Rr as normalizeTextAmplifiers, Rt as DEFAULT_BYPASS_OPTIONS, S as snapToMidpointPerpendicular, Sn as SupportingAttackOptions, Sr as ControlMeasureGeometry, St as DEFAULT_ANTITANK_DITCH_OPTIONS, T as BaselineFrameOptions, Tn as calculateMetrics, Tr as ControlMeasurePaintCapability, Tt as DEFAULT_GUARD_OPTIONS, U as CONTROL_MEASURE_METADATA, Un as ControlMeasureRender, Ut as BattleHandoverLineOptions, V as isKind, Vn as DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, Vr as ControlMeasureDrawRule, Vt as BlockMissionTaskOptions, W as ControlMeasureId, Wn as FeaturePartProps, Wt as DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS, X as listControlMeasureMetadata, Xn as DirectionOfSupportingAttackOptions, Xt as FLOTOptions, Y as getDefaultOptions, Yn as DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS, Yt as DEFAULT_FLOT_OPTIONS, Z as DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, Zn as DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS, Zt as AttackByFireOptions, _ as MidpointPerpendicularDrawRuleOptions, _n as DEFAULT_BLOCK_ARROW_OPTIONS, _r as unproject, _t as DEFAULT_FORTIFIED_LINE_OPTIONS, a as supportByFireDrawRule, an as DEFAULT_GENERIC_TEXT_OPTIONS, ar as ControlMeasureStyle, at as DEFAULT_FIX_OPTIONS, b as getMidpointPerpendicularSignedDistance, bn as DEFAULT_CLASSIC_ARROW_OPTIONS, br as BoxTransformDelta, bt as DEFAULT_ANTITANK_WALL_OPTIONS, c as line23DrawRule, cn as GenericCircleOptions, cr as GenericC2LineOptions, ct as DisruptOptions, d as ambushDrawRule, dn as DEFAULT_GENERIC_POLYGON_OPTIONS, dr as DEFAULT_LIGHT_LINE_OPTIONS, dt as DEFAULT_TURNING_MOVEMENT_OPTIONS, en as SupportByFireOptions, er as DirectionOfAttackAviationOptions, et as ObstacleBypassDifficultOptions, f as attackByFireDrawRule, fn as GenericPolygonOptions, fr as LightLineOptions, ft as TurningMovementOptions, g as blockDrawRule, gn as BlockArrowOptions, gr as project, gt as FortifiedAreaOptions, h as disruptDrawRule, hn as BlockArrowHeadStyle, hr as haversineDistance, ht as DEFAULT_FORTIFIED_AREA_OPTIONS, i as axis1DrawRule, in as DEFAULT_AIRBORNE_ATTACK_OPTIONS, ir as DEFAULT_BATTLE_POSITION_OPTIONS, it as TurnOptions, j as SimpleStyleProps, jn as DEFAULT_LANDING_ZONE_OPTIONS, jr as GeneratedLabelKey, jt as DEFAULT_TACTICAL_ARROW_OPTIONS, k as getMetersPerPixel, kn as DEFAULT_PICKUP_ZONE_OPTIONS, kr as AmplifierPlacements, kt as CoverOptions, l as turnDrawRule, ln as DEFAULT_GENERIC_RECTANGLE_OPTIONS, lr as DEFAULT_ENGINEER_WORK_LINE_OPTIONS, lt as BlockOptions, m as centerRadiusDrawRule, mn as GenericLineOptions, mr as Point2D, mt as FrontalAttackOptions, n as DEFAULT_AMBUSH_OPTIONS, nn as DEFAULT_ATTACK_HELICOPTER_OPTIONS, nr as StrongPointOptions, nt as ObstacleBypassEasyOptions, o as line26DrawRule, on as GenericTextOptions, or as FillPattern, ot as FixOptions, p as point12DrawRule, pn as DEFAULT_GENERIC_LINE_OPTIONS, pr as LabelSizeOptions, pt as DEFAULT_FRONTAL_ATTACK_OPTIONS, q as getControlMeasureMetadata, qn as DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, qt as DEFAULT_PHASE_LINE_OPTIONS, r as rectangleDrawRule, rn as AirborneAttackOptions, rr as BattlePositionOptions, rt as DEFAULT_TURN_OPTIONS, s as line24DrawRule, sn as DEFAULT_GENERIC_CIRCLE_OPTIONS, sr as DEFAULT_GENERIC_C2_LINE_OPTIONS, st as DEFAULT_DISRUPT_OPTIONS, t as AmbushOptions, tn as AttackHelicopterOptions, tr as DEFAULT_STRONG_POINT_OPTIONS, tt as DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, u as line1DrawRule, un as GenericRectangleOptions, ur as EngineerWorkLineOptions, ut as DEFAULT_BLOCK_OPTIONS, v as computeDefaultMidpointPerpendicularPoint, vn as ClassicArrowHeadStyle, vr as BoundaryOptions, vt as FortifiedLineOptions, w as BaselineFrameNormal, wn as MainAttackOptions, wr as ControlMeasureMetadata, wt as ScreenOptions, x as pointOnMidpointPerpendicularAxis, xn as DEFAULT_SUPPORTING_ATTACK_OPTIONS, xr as ControlMeasureFillCapability, xt as AntitankDitchOptions, y as createMidpointPerpendicularDrawRule, yn as ClassicArrowOptions, yr as DEFAULT_BOUNDARY_OPTIONS, yt as AntitankWallOptions, z as ControlMeasure, zn as DEFAULT_ENCIRCLEMENT_OPTIONS, zr as resolveAmplifierPlacement, zt as BreachOptions } from "./index-DmAFButD.mjs";
|
|
2
2
|
export { type AirborneAttackOptions, type AmbushOptions, type AmplifierPlacement, type AmplifierPlacements, type AnchorTransformEvent, type AntitankDitchOptions, type AntitankWallOptions, type AreaDefenseOptions, type AreaOfOperationsOptions, type AssemblyAreaOptions, type AttackByFireOptions, type AttackHelicopterOptions, type BaselineFrame, type BaselineFrameNormal, type BaselineFrameOptions, type BaselineFrameOrigin, type BattleHandoverLineOptions, type BattlePositionOptions, type BlockArrowHeadStyle, type BlockArrowOptions, type BlockMissionTaskOptions, type BlockOptions, type BoundaryOptions, type BoxTransformDelta, type BreachOptions, type BypassOptions, CONTROL_MEASURE_IDS, CONTROL_MEASURE_METADATA, type CanalizeOptions, type CanonicalTextAmplifiers, type ClassicArrowHeadStyle, type ClassicArrowOptions, type ClearOptions, type ControlMeasure, type ControlMeasureDrawRule, type ControlMeasureFillCapability, type ControlMeasureGeometry, type ControlMeasureGeometryType, type ControlMeasureId, type ControlMeasureKind, type ControlMeasureMetadata, type ControlMeasurePaintCapability, type ControlMeasureRender, type ControlMeasureStyle, type CoverOptions, DEFAULT_AIRBORNE_ATTACK_OPTIONS, DEFAULT_AMBUSH_OPTIONS, DEFAULT_ANTITANK_DITCH_OPTIONS, DEFAULT_ANTITANK_WALL_OPTIONS, DEFAULT_AREA_DEFENSE_OPTIONS, DEFAULT_AREA_OF_OPERATIONS_OPTIONS, DEFAULT_ASSEMBLY_AREA_OPTIONS, DEFAULT_ATTACK_BY_FIRE_OPTIONS, DEFAULT_ATTACK_HELICOPTER_OPTIONS, DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS, DEFAULT_BATTLE_POSITION_OPTIONS, DEFAULT_BLOCK_ARROW_OPTIONS, DEFAULT_BLOCK_MISSION_TASK_OPTIONS, DEFAULT_BLOCK_OPTIONS, DEFAULT_BOUNDARY_OPTIONS, DEFAULT_BREACH_OPTIONS, DEFAULT_BYPASS_OPTIONS, DEFAULT_CANALIZE_OPTIONS, DEFAULT_CLASSIC_ARROW_OPTIONS, DEFAULT_CLEAR_OPTIONS, DEFAULT_COVER_OPTIONS, DEFAULT_DELAY_OPTIONS, DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS, DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS, DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS, DEFAULT_DISRUPT_OPTIONS, DEFAULT_ENCIRCLEMENT_OPTIONS, DEFAULT_ENGINEER_WORK_LINE_OPTIONS, DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, DEFAULT_FIX_OPTIONS, DEFAULT_FLOT_OPTIONS, DEFAULT_FORTIFIED_AREA_OPTIONS, DEFAULT_FORTIFIED_LINE_OPTIONS, DEFAULT_FRONTAL_ATTACK_OPTIONS, DEFAULT_GENERIC_C2_LINE_OPTIONS, DEFAULT_GENERIC_CIRCLE_OPTIONS, DEFAULT_GENERIC_LINE_OPTIONS, DEFAULT_GENERIC_POLYGON_OPTIONS, DEFAULT_GENERIC_RECTANGLE_OPTIONS, DEFAULT_GENERIC_TEXT_OPTIONS, DEFAULT_GUARD_OPTIONS, DEFAULT_HANDOVER_LINE_OPTIONS, DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS, DEFAULT_LANDING_ZONE_OPTIONS, DEFAULT_LIGHT_LINE_OPTIONS, DEFAULT_MAIN_ATTACK_OPTIONS, DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, DEFAULT_PHASE_LINE_OPTIONS, DEFAULT_PICKUP_ZONE_OPTIONS, DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, DEFAULT_SCREEN_OPTIONS, DEFAULT_STRONG_POINT_OPTIONS, DEFAULT_SUPPORTING_ATTACK_OPTIONS, DEFAULT_SUPPORT_BY_FIRE_OPTIONS, DEFAULT_TACTICAL_ARROW_OPTIONS, DEFAULT_TURNING_MOVEMENT_OPTIONS, DEFAULT_TURN_OPTIONS, type DelayOptions, type DirectionOfAttackAviationOptions, type DirectionOfMainAttackOptions, type DirectionOfSupportingAttackOptions, type DisruptOptions, EPSILON, type EncirclementOptions, type EngineerWorkLineOptions, type FLOTOptions, type FeaturePartProps, type FillPattern, type FinalProtectiveFireOptions, type FixOptions, type FortifiedAreaOptions, type FortifiedLineOptions, type FrontalAttackOptions, type GeneratedLabelKey, type GenericC2LineOptions, type GenericCircleOptions, type GenericLineOptions, type GenericPolygonOptions, type GenericRectangleOptions, type GenericTextOptions, type GuardOptions, type HandoverLineOptions, type JointTacticalActionAreaOptions, type LabelPlacementOverride, type LabelSizeOptions, type LandingZoneOptions, type LightLineOptions, type MainAttackOptions, type MidpointPerpendicularDrawRuleOptions, type ObstacleBypassDifficultOptions, type ObstacleBypassEasyOptions, type ObstacleBypassImpossibleOptions, type OptionsByKind, type ParamDescriptor, type PhaseLineOptions, type PickupZoneOptions, type Point2D, type PrincipalDirectionOfFireOptions, type RenderOptions, type ScreenOptions, type SimpleStyleProps, type SimpleStyleRender, type StrongPointOptions, type StyleHints, type SupportByFireOptions, type SupportingAttackOptions, TEXT_AMPLIFIER_FIELDS, type TacticalArrowOptions, type TextAmplifierDescriptor, type TextAmplifierField, type TextAmplifierKey, type TextAmplifiers, type TurnOptions, type TurningMovementOptions, ambushDrawRule, applyBoxTransformOptions, attackByFireDrawRule, axis1DrawRule, blockDrawRule, calculateMetrics, canonicalTextAmplifierKey, centerRadiusDrawRule, cloneControlMeasure, computeDefaultMidpointPerpendicularPoint, computeInitialWidthPoint, controlMeasureIdFromFeature, createBaselineFrame, createMidpointPerpendicularDrawRule, disruptDrawRule, freezeOrientationOptions, getControlMeasureMetadata, getControlMeasureMetadataByValue, getDefaultOptions, getMetersPerPixel, getMidpointPerpendicularSignedDistance, haversineDistance, isKind, line1DrawRule, line23DrawRule, line24DrawRule, line26DrawRule, listControlMeasureMetadata, normalizeTextAmplifiers, point12DrawRule, pointOnMidpointPerpendicularAxis, project, rectangleDrawRule, renderControlMeasure, resolveAmplifierPlacement, resolveStyleHints, roundToFixed, snapToMidpointPerpendicular, supportByFireDrawRule, toSimpleStyle, turnDrawRule, unproject };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as DEFAULT_BOUNDARY_OPTIONS, A as DEFAULT_FLOT_OPTIONS, At as centerRadiusDrawRule, B as DEFAULT_GENERIC_TEXT_OPTIONS, Bt as computeInitialWidthPoint, C as DEFAULT_SCREEN_OPTIONS, Ct as line24DrawRule, D as DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS, Dt as ambushDrawRule, E as DEFAULT_FORTIFIED_LINE_OPTIONS, Et as line1DrawRule, F as DEFAULT_GUARD_OPTIONS, Ft as getMidpointPerpendicularSignedDistance, G as DEFAULT_CLASSIC_ARROW_OPTIONS, Gt as getMetersPerPixel, H as DEFAULT_GENERIC_POLYGON_OPTIONS, Ht as project, I as DEFAULT_DELAY_OPTIONS, It as pointOnMidpointPerpendicularAxis, J as DEFAULT_BREACH_OPTIONS, K as DEFAULT_CANALIZE_OPTIONS, Kt as roundToFixed, L as DEFAULT_COVER_OPTIONS, Lt as snapToMidpointPerpendicular, M as DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, Mt as blockDrawRule, N as DEFAULT_ENCIRCLEMENT_OPTIONS, Nt as computeDefaultMidpointPerpendicularPoint, O as DEFAULT_HANDOVER_LINE_OPTIONS, Ot as attackByFireDrawRule, P as DEFAULT_DISRUPT_OPTIONS, Pt as createMidpointPerpendicularDrawRule, Q as DEFAULT_LIGHT_LINE_OPTIONS, R as DEFAULT_TACTICAL_ARROW_OPTIONS, Rt as createBaselineFrame, S as DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS, St as line26DrawRule, T as DEFAULT_FORTIFIED_AREA_OPTIONS, Tt as turnDrawRule, U as DEFAULT_GENERIC_LINE_OPTIONS, Ut as unproject, V as DEFAULT_GENERIC_RECTANGLE_OPTIONS, Vt as haversineDistance, W as DEFAULT_GENERIC_CIRCLE_OPTIONS, Wt as EPSILON, X as DEFAULT_GENERIC_C2_LINE_OPTIONS, Y as DEFAULT_BLOCK_MISSION_TASK_OPTIONS, Z as DEFAULT_ENGINEER_WORK_LINE_OPTIONS, _ as DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, _t as DEFAULT_AMBUSH_OPTIONS, a as DEFINITIONS, at as DEFAULT_ANTITANK_WALL_OPTIONS, b as DEFAULT_MAIN_ATTACK_OPTIONS, bt as axis1DrawRule, c as getDefaultOptions, ct as DEFAULT_AREA_OF_OPERATIONS_OPTIONS, d as DEFAULT_TURN_OPTIONS, dt as
|
|
1
|
+
import { $ as DEFAULT_BOUNDARY_OPTIONS, A as DEFAULT_FLOT_OPTIONS, At as centerRadiusDrawRule, B as DEFAULT_GENERIC_TEXT_OPTIONS, Bt as computeInitialWidthPoint, C as DEFAULT_SCREEN_OPTIONS, Ct as line24DrawRule, D as DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS, Dt as ambushDrawRule, E as DEFAULT_FORTIFIED_LINE_OPTIONS, Et as line1DrawRule, F as DEFAULT_GUARD_OPTIONS, Ft as getMidpointPerpendicularSignedDistance, G as DEFAULT_CLASSIC_ARROW_OPTIONS, Gt as getMetersPerPixel, H as DEFAULT_GENERIC_POLYGON_OPTIONS, Ht as project, I as DEFAULT_DELAY_OPTIONS, It as pointOnMidpointPerpendicularAxis, J as DEFAULT_BREACH_OPTIONS, K as DEFAULT_CANALIZE_OPTIONS, Kt as roundToFixed, L as DEFAULT_COVER_OPTIONS, Lt as snapToMidpointPerpendicular, M as DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, Mt as blockDrawRule, N as DEFAULT_ENCIRCLEMENT_OPTIONS, Nt as computeDefaultMidpointPerpendicularPoint, O as DEFAULT_HANDOVER_LINE_OPTIONS, Ot as attackByFireDrawRule, P as DEFAULT_DISRUPT_OPTIONS, Pt as createMidpointPerpendicularDrawRule, Q as DEFAULT_LIGHT_LINE_OPTIONS, R as DEFAULT_TACTICAL_ARROW_OPTIONS, Rt as createBaselineFrame, S as DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS, St as line26DrawRule, T as DEFAULT_FORTIFIED_AREA_OPTIONS, Tt as turnDrawRule, U as DEFAULT_GENERIC_LINE_OPTIONS, Ut as unproject, V as DEFAULT_GENERIC_RECTANGLE_OPTIONS, Vt as haversineDistance, W as DEFAULT_GENERIC_CIRCLE_OPTIONS, Wt as EPSILON, X as DEFAULT_GENERIC_C2_LINE_OPTIONS, Y as DEFAULT_BLOCK_MISSION_TASK_OPTIONS, Z as DEFAULT_ENGINEER_WORK_LINE_OPTIONS, _ as DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, _t as DEFAULT_AMBUSH_OPTIONS, a as DEFINITIONS, at as DEFAULT_ANTITANK_WALL_OPTIONS, b as DEFAULT_MAIN_ATTACK_OPTIONS, bt as axis1DrawRule, c as getDefaultOptions, ct as DEFAULT_AREA_OF_OPERATIONS_OPTIONS, d as DEFAULT_TURN_OPTIONS, dt as DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS, et as DEFAULT_BLOCK_ARROW_OPTIONS, f as DEFAULT_SUPPORTING_ATTACK_OPTIONS, ft as DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS, g as DEFAULT_PICKUP_ZONE_OPTIONS, gt as resolveAmplifierPlacement, h as DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, ht as normalizeTextAmplifiers, i as CONTROL_MEASURE_METADATA, it as DEFAULT_ATTACK_BY_FIRE_OPTIONS, j as DEFAULT_FIX_OPTIONS, jt as disruptDrawRule, k as DEFAULT_PHASE_LINE_OPTIONS, kt as point12DrawRule, l as listControlMeasureMetadata, lt as DEFAULT_AREA_DEFENSE_OPTIONS, m as DEFAULT_STRONG_POINT_OPTIONS, mt as canonicalTextAmplifierKey, n as resolveStyleHints, nt as DEFAULT_BATTLE_POSITION_OPTIONS, o as getControlMeasureMetadata, ot as DEFAULT_ANTITANK_DITCH_OPTIONS, p as DEFAULT_SUPPORT_BY_FIRE_OPTIONS, pt as TEXT_AMPLIFIER_FIELDS, q as DEFAULT_BYPASS_OPTIONS, r as CONTROL_MEASURE_IDS, rt as DEFAULT_ATTACK_HELICOPTER_OPTIONS, s as getControlMeasureMetadataByValue, st as DEFAULT_ASSEMBLY_AREA_OPTIONS, t as renderControlMeasure, tt as DEFAULT_BLOCK_OPTIONS, u as DEFAULT_TURNING_MOVEMENT_OPTIONS, ut as DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS, v as DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, vt as DEFAULT_AIRBORNE_ATTACK_OPTIONS, w as DEFAULT_FRONTAL_ATTACK_OPTIONS, wt as line23DrawRule, x as DEFAULT_LANDING_ZONE_OPTIONS, xt as supportByFireDrawRule, y as DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, yt as rectangleDrawRule, z as DEFAULT_CLEAR_OPTIONS, zt as calculateMetrics } from "./renderControlMeasure-CzhJJJHO.mjs";
|
|
2
2
|
//#region src/freeze-orientation.ts
|
|
3
3
|
/**
|
|
4
4
|
* Dispatches to a measure kind's `freezeOrientation` hook (see
|
package/dist/preview/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ir as TextAmplifiers, W as ControlMeasureId, or as FillPattern } from "../index-
|
|
1
|
+
import { Ir as TextAmplifiers, W as ControlMeasureId, or as FillPattern } from "../index-DmAFButD.mjs";
|
|
2
2
|
import { FeatureCollection, Geometry } from "geojson";
|
|
3
3
|
|
|
4
4
|
//#region src/preview/index.d.ts
|
package/dist/preview/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as DEFINITIONS, t as renderControlMeasure } from "../renderControlMeasure-
|
|
1
|
+
import { a as DEFINITIONS, t as renderControlMeasure } from "../renderControlMeasure-CzhJJJHO.mjs";
|
|
2
2
|
//#region src/preview/index.ts
|
|
3
3
|
/** Side length (SVG units) of the repeating hatch tile in {@link PREVIEW_FILL_PATTERNS}. */
|
|
4
4
|
const PREVIEW_PATTERN_TILE = 8;
|
|
@@ -2199,6 +2199,80 @@ function endTangents(verts) {
|
|
|
2199
2199
|
}
|
|
2200
2200
|
};
|
|
2201
2201
|
}
|
|
2202
|
+
/** Nearest contact point on a polyline for a dragged label anchor. */
|
|
2203
|
+
function nearestPointOnPolyline(verts, target) {
|
|
2204
|
+
let nearest;
|
|
2205
|
+
let totalArc = 0;
|
|
2206
|
+
for (let i = 0; i < verts.length - 1; i++) {
|
|
2207
|
+
const a = verts[i];
|
|
2208
|
+
const b = verts[i + 1];
|
|
2209
|
+
const seg = vecSub(b, a);
|
|
2210
|
+
const length = vecMag(seg);
|
|
2211
|
+
if (length < 1e-6) continue;
|
|
2212
|
+
const along = vecScale(seg, 1 / length);
|
|
2213
|
+
const t = Math.max(0, Math.min(length, vecDot(vecSub(target, a), along)));
|
|
2214
|
+
const distance = vecMag(vecSub(target, vecAdd(a, vecScale(along, t))));
|
|
2215
|
+
if (!nearest || distance < nearest.distance) nearest = {
|
|
2216
|
+
along,
|
|
2217
|
+
arc: totalArc + t,
|
|
2218
|
+
distance,
|
|
2219
|
+
edge: [a, b]
|
|
2220
|
+
};
|
|
2221
|
+
totalArc += length;
|
|
2222
|
+
}
|
|
2223
|
+
return nearest ? {
|
|
2224
|
+
...nearest,
|
|
2225
|
+
totalArc
|
|
2226
|
+
} : void 0;
|
|
2227
|
+
}
|
|
2228
|
+
/**
|
|
2229
|
+
* Half-extent of a possibly rotated `textWidth × textHeight` label box along
|
|
2230
|
+
* `direction` (the box's support function): a boundary running parallel to the
|
|
2231
|
+
* text needs roughly the label's width, one running perpendicular roughly its
|
|
2232
|
+
* height. `rotation` is the label's stored rotation — adapters render the
|
|
2233
|
+
* on-screen angle as `π − rotation`, and the absolute-value projections make
|
|
2234
|
+
* the result invariant under that sign convention.
|
|
2235
|
+
*/
|
|
2236
|
+
function labelHalfExtent(direction, textWidth, textHeight, rotation) {
|
|
2237
|
+
const [widthAxis, heightAxis] = labelBoxAxes(rotation);
|
|
2238
|
+
return boxSupport(direction, textWidth, textHeight, widthAxis, heightAxis);
|
|
2239
|
+
}
|
|
2240
|
+
/** The label box's local axes for a stored `rotation`: the along-text width
|
|
2241
|
+
* axis and its perpendicular height axis. */
|
|
2242
|
+
function labelBoxAxes(rotation) {
|
|
2243
|
+
const widthAxis = [Math.cos(rotation), Math.sin(rotation)];
|
|
2244
|
+
return [widthAxis, [-widthAxis[1], widthAxis[0]]];
|
|
2245
|
+
}
|
|
2246
|
+
/** {@link labelHalfExtent} over already-resolved box axes. */
|
|
2247
|
+
function boxSupport(direction, textWidth, textHeight, widthAxis, heightAxis) {
|
|
2248
|
+
return .5 * (textWidth * Math.abs(vecDot(direction, widthAxis)) + textHeight * Math.abs(vecDot(direction, heightAxis)));
|
|
2249
|
+
}
|
|
2250
|
+
/**
|
|
2251
|
+
* Whether a `textWidth × textHeight` label box centered at `anchor` with
|
|
2252
|
+
* stored `rotation` overlaps the finite segment `[a, b]` — an exact
|
|
2253
|
+
* separating-axis test over the box's two axes plus the segment's normal.
|
|
2254
|
+
* The normal support alone (see {@link labelHalfExtent}) only tests against
|
|
2255
|
+
* the segment's infinite line: past an endpoint the anchor→contact offset is
|
|
2256
|
+
* tangential and that scalar comparison wrongly reads as clear, so masking
|
|
2257
|
+
* decisions must use this finite-segment test instead.
|
|
2258
|
+
*/
|
|
2259
|
+
function labelBoxIntersectsSegment(anchor, a, b, textWidth, textHeight, rotation) {
|
|
2260
|
+
const seg = vecSub(b, a);
|
|
2261
|
+
const length = vecMag(seg);
|
|
2262
|
+
const [widthAxis, heightAxis] = labelBoxAxes(rotation);
|
|
2263
|
+
const ra = vecSub(a, anchor);
|
|
2264
|
+
if (length < 1e-6) return Math.abs(vecDot(ra, widthAxis)) <= textWidth / 2 && Math.abs(vecDot(ra, heightAxis)) <= textHeight / 2;
|
|
2265
|
+
const along = vecScale(seg, 1 / length);
|
|
2266
|
+
const normal = [-along[1], along[0]];
|
|
2267
|
+
if (Math.abs(vecDot(ra, normal)) > boxSupport(normal, textWidth, textHeight, widthAxis, heightAxis)) return false;
|
|
2268
|
+
const rb = vecSub(b, anchor);
|
|
2269
|
+
for (const [axis, half] of [[widthAxis, textWidth / 2], [heightAxis, textHeight / 2]]) {
|
|
2270
|
+
const pa = vecDot(ra, axis);
|
|
2271
|
+
const pb = vecDot(rb, axis);
|
|
2272
|
+
if (Math.min(pa, pb) > half || Math.max(pa, pb) < -half) return false;
|
|
2273
|
+
}
|
|
2274
|
+
return true;
|
|
2275
|
+
}
|
|
2202
2276
|
/** Field N descriptor shared by Line1 graphics that opt into hostile endpoint markers. */
|
|
2203
2277
|
const HOSTILE_LINE_AMPLIFIER = {
|
|
2204
2278
|
key: "N",
|
|
@@ -2419,6 +2493,141 @@ function fixedLabelLineFeatures(positions, options, textForEnd, hostileText) {
|
|
|
2419
2493
|
};
|
|
2420
2494
|
}
|
|
2421
2495
|
//#endregion
|
|
2496
|
+
//#region src/text-amplifiers.ts
|
|
2497
|
+
/**
|
|
2498
|
+
* The vocabulary of text amplifier fields: doctrinal code, milsymbol-style
|
|
2499
|
+
* friendly alias, and a human-readable label. The single source of truth for
|
|
2500
|
+
* both the runtime catalog and the derived alias→code lookup used by
|
|
2501
|
+
* {@link normalizeTextAmplifiers}.
|
|
2502
|
+
*/
|
|
2503
|
+
const TEXT_AMPLIFIER_FIELDS = {
|
|
2504
|
+
C: {
|
|
2505
|
+
alias: "quantity",
|
|
2506
|
+
label: "Quantity"
|
|
2507
|
+
},
|
|
2508
|
+
H: {
|
|
2509
|
+
alias: "additionalInformation",
|
|
2510
|
+
label: "Additional information"
|
|
2511
|
+
},
|
|
2512
|
+
N: {
|
|
2513
|
+
alias: "hostile",
|
|
2514
|
+
label: "Hostile (ENY) marker"
|
|
2515
|
+
},
|
|
2516
|
+
T: {
|
|
2517
|
+
alias: "uniqueDesignation",
|
|
2518
|
+
label: "Unique designation"
|
|
2519
|
+
},
|
|
2520
|
+
V: {
|
|
2521
|
+
alias: "type",
|
|
2522
|
+
label: "Equipment/type"
|
|
2523
|
+
},
|
|
2524
|
+
W: {
|
|
2525
|
+
alias: "dtg",
|
|
2526
|
+
label: "Date-time group / O/O"
|
|
2527
|
+
},
|
|
2528
|
+
X: {
|
|
2529
|
+
alias: "altitudeDepth",
|
|
2530
|
+
label: "Altitude/depth"
|
|
2531
|
+
},
|
|
2532
|
+
Y: {
|
|
2533
|
+
alias: "location",
|
|
2534
|
+
label: "Location"
|
|
2535
|
+
},
|
|
2536
|
+
AM: {
|
|
2537
|
+
alias: "distance",
|
|
2538
|
+
label: "Distance/range/radius"
|
|
2539
|
+
},
|
|
2540
|
+
AN: {
|
|
2541
|
+
alias: "azimuth",
|
|
2542
|
+
label: "Azimuth"
|
|
2543
|
+
},
|
|
2544
|
+
AP: {
|
|
2545
|
+
alias: "targetNumber",
|
|
2546
|
+
label: "Target number"
|
|
2547
|
+
},
|
|
2548
|
+
AS: {
|
|
2549
|
+
alias: "country",
|
|
2550
|
+
label: "Country code"
|
|
2551
|
+
}
|
|
2552
|
+
};
|
|
2553
|
+
/** Derived alias→code lookup, so the vocabulary table stays the single source of truth. */
|
|
2554
|
+
const CODE_BY_ALIAS = Object.fromEntries(Object.entries(TEXT_AMPLIFIER_FIELDS).map(([code, { alias }]) => [alias, code]));
|
|
2555
|
+
const CANONICAL_KEYS = new Set(Object.keys(TEXT_AMPLIFIER_FIELDS).flatMap((code) => [
|
|
2556
|
+
code,
|
|
2557
|
+
`${code}1`,
|
|
2558
|
+
`${code}2`
|
|
2559
|
+
]));
|
|
2560
|
+
/**
|
|
2561
|
+
* Resolves a raw placement entry to its object form: a bare `Position` is
|
|
2562
|
+
* legacy shorthand for `{ position }`; an object form passes through only the
|
|
2563
|
+
* fields that are actually valid (`position` must be a finite `[lon, lat]`,
|
|
2564
|
+
* `rotation` a finite number); `undefined` resolves to `{}`.
|
|
2565
|
+
*/
|
|
2566
|
+
function resolveAmplifierPlacement(value) {
|
|
2567
|
+
if (value === void 0) return {};
|
|
2568
|
+
if (Array.isArray(value)) return isValidPosition(value) ? { position: value } : {};
|
|
2569
|
+
const result = {};
|
|
2570
|
+
if (value.position !== void 0 && isValidPosition(value.position)) result.position = value.position;
|
|
2571
|
+
if (typeof value.rotation === "number" && Number.isFinite(value.rotation)) result.rotation = value.rotation;
|
|
2572
|
+
return result;
|
|
2573
|
+
}
|
|
2574
|
+
const EMPTY_TEXT_AMPLIFIERS = Object.freeze({});
|
|
2575
|
+
/** Splits a key like `"country1"` into its base (`"country"`) and suffix (`"1"`). */
|
|
2576
|
+
function splitSuffix(key) {
|
|
2577
|
+
const last = key.charAt(key.length - 1);
|
|
2578
|
+
if (last === "1" || last === "2") return {
|
|
2579
|
+
base: key.slice(0, -1),
|
|
2580
|
+
suffix: last
|
|
2581
|
+
};
|
|
2582
|
+
return {
|
|
2583
|
+
base: key,
|
|
2584
|
+
suffix: ""
|
|
2585
|
+
};
|
|
2586
|
+
}
|
|
2587
|
+
/**
|
|
2588
|
+
* Resolves any accepted key (canonical or friendly alias, with an optional
|
|
2589
|
+
* `1`/`2` suffix) to its canonical key, or `undefined` if unknown — e.g.
|
|
2590
|
+
* `"T"` → `"T"`, `"uniqueDesignation1"` → `"T1"`, `"bogus"` → `undefined`.
|
|
2591
|
+
*/
|
|
2592
|
+
function canonicalTextAmplifierKey(key) {
|
|
2593
|
+
if (CANONICAL_KEYS.has(key)) return key;
|
|
2594
|
+
const { base, suffix } = splitSuffix(key);
|
|
2595
|
+
const code = CODE_BY_ALIAS[base];
|
|
2596
|
+
return code ? `${code}${suffix}` : void 0;
|
|
2597
|
+
}
|
|
2598
|
+
/**
|
|
2599
|
+
* Resolves a `TextAmplifiers` record (canonical keys, friendly aliases, or a
|
|
2600
|
+
* mix) to `CanonicalTextAmplifiers` keyed purely by doctrinal field code.
|
|
2601
|
+
*
|
|
2602
|
+
* - Friendly aliases (with an optional `1`/`2` suffix) map to their canonical
|
|
2603
|
+
* code (e.g. `country1` → `AS1`).
|
|
2604
|
+
* - Values are trimmed; entries that are empty/whitespace-only after
|
|
2605
|
+
* trimming, or not strings, are dropped.
|
|
2606
|
+
* - When both a canonical key and its friendly alias are present for the same
|
|
2607
|
+
* field + suffix, the **canonical key wins** regardless of insertion order.
|
|
2608
|
+
* This holds even for an empty/whitespace canonical value: it suppresses
|
|
2609
|
+
* (clears) the alias entry rather than letting the alias survive.
|
|
2610
|
+
* - Unknown keys are ignored.
|
|
2611
|
+
*
|
|
2612
|
+
* `undefined` or an empty input returns a shared frozen empty object.
|
|
2613
|
+
*/
|
|
2614
|
+
function normalizeTextAmplifiers(input) {
|
|
2615
|
+
if (!input) return EMPTY_TEXT_AMPLIFIERS;
|
|
2616
|
+
const canonicalPresent = /* @__PURE__ */ new Set();
|
|
2617
|
+
for (const [key, rawValue] of Object.entries(input)) if (typeof rawValue === "string" && CANONICAL_KEYS.has(key)) canonicalPresent.add(key);
|
|
2618
|
+
const result = {};
|
|
2619
|
+
for (const [key, rawValue] of Object.entries(input)) {
|
|
2620
|
+
if (typeof rawValue !== "string") continue;
|
|
2621
|
+
const value = rawValue.trim();
|
|
2622
|
+
if (value.length === 0) continue;
|
|
2623
|
+
const canonicalKey = canonicalTextAmplifierKey(key);
|
|
2624
|
+
if (!canonicalKey) continue;
|
|
2625
|
+
if (!CANONICAL_KEYS.has(key) && canonicalPresent.has(canonicalKey)) continue;
|
|
2626
|
+
result[canonicalKey] = value;
|
|
2627
|
+
}
|
|
2628
|
+
return Object.keys(result).length > 0 ? Object.freeze(result) : EMPTY_TEXT_AMPLIFIERS;
|
|
2629
|
+
}
|
|
2630
|
+
//#endregion
|
|
2422
2631
|
//#region src/generators/cm14-maneuver-lines/direction-of-attack-shared.ts
|
|
2423
2632
|
const DEFAULT_DIRECTION_ARROWHEAD_LENGTH_RATIO = .12;
|
|
2424
2633
|
const DEFAULT_DIRECTION_ARROWHEAD_WIDTH_RATIO = 1.15;
|
|
@@ -2428,20 +2637,46 @@ const LABEL_GAP_CLEARANCE_RATIO = .3;
|
|
|
2428
2637
|
function nonNegative$1(value, fallback) {
|
|
2429
2638
|
return Number.isFinite(value) ? Math.max(0, value) : fallback;
|
|
2430
2639
|
}
|
|
2431
|
-
/**
|
|
2432
|
-
|
|
2640
|
+
/**
|
|
2641
|
+
* Arc-length knockout for the Field T text label, mirroring the area measures'
|
|
2642
|
+
* ENY-marker masking (`pushAreaLabels`). By default the gap is centered on the
|
|
2643
|
+
* label's along-route anchor at `fraction`. A dragged label (a persisted `T`
|
|
2644
|
+
* placement position) instead contacts the route at its nearest point: the gap
|
|
2645
|
+
* follows the label there, and once the label's estimated text box no longer
|
|
2646
|
+
* touches the route the gap disappears and the line closes. The gap is sized
|
|
2647
|
+
* as the support function of the (possibly rotated) text box along the
|
|
2648
|
+
* contacted edge's direction ({@link labelHalfExtent}), plus clearance.
|
|
2649
|
+
*
|
|
2650
|
+
* `verts` is the polyline the gap is carved from (arc lengths must match the
|
|
2651
|
+
* later `buildGappedLine` walk); `segments`/`totalLength` describe the full
|
|
2652
|
+
* route that anchors the default label placement.
|
|
2653
|
+
*/
|
|
2654
|
+
function directionLabelGap(verts, segments, totalLength, fraction, text, options, placement = {}) {
|
|
2433
2655
|
if (!text) return void 0;
|
|
2434
2656
|
const textHeight = resolveLabelOffsetMeters(options, 1);
|
|
2435
2657
|
const textWidth = estimatedTextWidth(text, textHeight);
|
|
2436
2658
|
const clearance = (LABEL_GAP_CLEARANCE_RATIO + Math.max(0, options.labelPadding ?? 0)) * textHeight;
|
|
2437
|
-
const
|
|
2659
|
+
const frame = pointAlongPolyline(segments, totalLength, fraction);
|
|
2660
|
+
const rotation = placement.rotation ?? (frame ? labelRotationAlong(frame.along) : 0);
|
|
2661
|
+
if (placement.position) {
|
|
2662
|
+
const anchor = project(placement.position[0], placement.position[1]);
|
|
2663
|
+
const contact = nearestPointOnPolyline(verts, anchor);
|
|
2664
|
+
if (!contact) return void 0;
|
|
2665
|
+
if (!labelBoxIntersectsSegment(anchor, ...contact.edge, textWidth, textHeight, rotation)) return;
|
|
2666
|
+
const halfGap = labelHalfExtent(contact.along, textWidth, textHeight, rotation) + clearance;
|
|
2667
|
+
return {
|
|
2668
|
+
g0: Math.max(0, contact.arc - halfGap),
|
|
2669
|
+
g1: Math.min(contact.totalArc, contact.arc + halfGap)
|
|
2670
|
+
};
|
|
2671
|
+
}
|
|
2672
|
+
const halfGap = frame ? labelHalfExtent(frame.along, textWidth, textHeight, rotation) + clearance : textWidth / 2 + clearance;
|
|
2438
2673
|
const center = fraction * totalLength;
|
|
2439
2674
|
return {
|
|
2440
2675
|
g0: Math.max(0, center - halfGap),
|
|
2441
2676
|
g1: Math.min(totalLength, center + halfGap)
|
|
2442
2677
|
};
|
|
2443
2678
|
}
|
|
2444
|
-
function createDirectionOfAttackLine(coordinates, options, textAmplifiers, config) {
|
|
2679
|
+
function createDirectionOfAttackLine(coordinates, options, textAmplifiers, config, context = {}) {
|
|
2445
2680
|
const verts = smoothLineVerts(coordinates.slice().reverse().map((position) => project(position[0], position[1])), options, 12);
|
|
2446
2681
|
const { segments, totalLength } = polylineSegments(verts);
|
|
2447
2682
|
if (segments.length === 0) return {
|
|
@@ -2480,7 +2715,7 @@ function createDirectionOfAttackLine(coordinates, options, textAmplifiers, confi
|
|
|
2480
2715
|
shaftVerts.push(innerTip);
|
|
2481
2716
|
}
|
|
2482
2717
|
const labelPosition = clampLinePosition(options.labelPosition, DEFAULT_DIRECTION_LABEL_POSITION);
|
|
2483
|
-
const labelGap = directionLabelGap(totalLength, labelPosition, textAmplifiers.T, options);
|
|
2718
|
+
const labelGap = directionLabelGap(shaftVerts, segments, totalLength, labelPosition, textAmplifiers.T, options, resolveAmplifierPlacement(context.amplifierPlacements?.T));
|
|
2484
2719
|
const lines = [...buildGappedLine(shaftVerts, labelGap ? [labelGap] : []), arrowhead.map((point) => unproject(point[0], point[1]))];
|
|
2485
2720
|
const features = [{
|
|
2486
2721
|
type: "Feature",
|
|
@@ -2712,7 +2947,7 @@ function pointAtDistance(verts, distance) {
|
|
|
2712
2947
|
return verts[verts.length - 1];
|
|
2713
2948
|
}
|
|
2714
2949
|
/** Builds the route, aviation bow-tie, arrowhead, and optional T/W/W1 labels. */
|
|
2715
|
-
function createDirectionOfAttackAviation(coordinates, options = {}, textAmplifiers = {}) {
|
|
2950
|
+
function createDirectionOfAttackAviation(coordinates, options = {}, textAmplifiers = {}, context = {}) {
|
|
2716
2951
|
const resolved = {
|
|
2717
2952
|
...DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS,
|
|
2718
2953
|
...options
|
|
@@ -2753,7 +2988,7 @@ function createDirectionOfAttackAviation(coordinates, options = {}, textAmplifie
|
|
|
2753
2988
|
const bowTieB = vecSub(bowTieStart, vecScale(bowTiePerp, bowTieHalfWidth));
|
|
2754
2989
|
const bowTieC = vecAdd(bowTieEnd, vecScale(bowTiePerp, bowTieHalfWidth));
|
|
2755
2990
|
const bowTieD = vecSub(bowTieEnd, vecScale(bowTiePerp, bowTieHalfWidth));
|
|
2756
|
-
const labelGap = directionLabelGap(totalLength, labelPosition, textAmplifiers.T, resolved);
|
|
2991
|
+
const labelGap = directionLabelGap(verts, segments, totalLength, labelPosition, textAmplifiers.T, resolved, resolveAmplifierPlacement(context.amplifierPlacements?.T));
|
|
2757
2992
|
const features = [{
|
|
2758
2993
|
type: "Feature",
|
|
2759
2994
|
properties: { part: "direction-of-attack-aviation" },
|
|
@@ -2854,7 +3089,7 @@ const DIRECTION_OF_MAIN_ATTACK_METADATA = {
|
|
|
2854
3089
|
],
|
|
2855
3090
|
textAmplifiers: DIRECTION_OF_ATTACK_TEXT_AMPLIFIERS
|
|
2856
3091
|
};
|
|
2857
|
-
function createDirectionOfMainAttack(coordinates, options = {}, textAmplifiers = {}) {
|
|
3092
|
+
function createDirectionOfMainAttack(coordinates, options = {}, textAmplifiers = {}, context = {}) {
|
|
2858
3093
|
const resolved = {
|
|
2859
3094
|
...DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS,
|
|
2860
3095
|
...options
|
|
@@ -2862,7 +3097,7 @@ function createDirectionOfMainAttack(coordinates, options = {}, textAmplifiers =
|
|
|
2862
3097
|
return createDirectionOfAttackLine(coordinates, resolved, textAmplifiers, {
|
|
2863
3098
|
part: "direction-of-main-attack",
|
|
2864
3099
|
outlineRatio: resolved.arrowheadOutlineRatio
|
|
2865
|
-
});
|
|
3100
|
+
}, context);
|
|
2866
3101
|
}
|
|
2867
3102
|
const DIRECTION_OF_MAIN_ATTACK = defineControlMeasure({
|
|
2868
3103
|
metadata: DIRECTION_OF_MAIN_ATTACK_METADATA,
|
|
@@ -2909,11 +3144,11 @@ const DIRECTION_OF_SUPPORTING_ATTACK_METADATA = {
|
|
|
2909
3144
|
params: [...SMOOTH_LINE_PARAMS, ...DIRECTION_OF_ATTACK_PARAMS],
|
|
2910
3145
|
textAmplifiers: DIRECTION_OF_ATTACK_TEXT_AMPLIFIERS
|
|
2911
3146
|
};
|
|
2912
|
-
function createDirectionOfSupportingAttack(coordinates, options = {}, textAmplifiers = {}) {
|
|
3147
|
+
function createDirectionOfSupportingAttack(coordinates, options = {}, textAmplifiers = {}, context = {}) {
|
|
2913
3148
|
return createDirectionOfAttackLine(coordinates, {
|
|
2914
3149
|
...DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS,
|
|
2915
3150
|
...options
|
|
2916
|
-
}, textAmplifiers, { part: "direction-of-supporting-attack" });
|
|
3151
|
+
}, textAmplifiers, { part: "direction-of-supporting-attack" }, context);
|
|
2917
3152
|
}
|
|
2918
3153
|
const DIRECTION_OF_SUPPORTING_ATTACK = defineControlMeasure({
|
|
2919
3154
|
metadata: DIRECTION_OF_SUPPORTING_ATTACK_METADATA,
|
|
@@ -2930,141 +3165,6 @@ const DIRECTION_OF_SUPPORTING_ATTACK = defineControlMeasure({
|
|
|
2930
3165
|
}
|
|
2931
3166
|
});
|
|
2932
3167
|
//#endregion
|
|
2933
|
-
//#region src/text-amplifiers.ts
|
|
2934
|
-
/**
|
|
2935
|
-
* The vocabulary of text amplifier fields: doctrinal code, milsymbol-style
|
|
2936
|
-
* friendly alias, and a human-readable label. The single source of truth for
|
|
2937
|
-
* both the runtime catalog and the derived alias→code lookup used by
|
|
2938
|
-
* {@link normalizeTextAmplifiers}.
|
|
2939
|
-
*/
|
|
2940
|
-
const TEXT_AMPLIFIER_FIELDS = {
|
|
2941
|
-
C: {
|
|
2942
|
-
alias: "quantity",
|
|
2943
|
-
label: "Quantity"
|
|
2944
|
-
},
|
|
2945
|
-
H: {
|
|
2946
|
-
alias: "additionalInformation",
|
|
2947
|
-
label: "Additional information"
|
|
2948
|
-
},
|
|
2949
|
-
N: {
|
|
2950
|
-
alias: "hostile",
|
|
2951
|
-
label: "Hostile (ENY) marker"
|
|
2952
|
-
},
|
|
2953
|
-
T: {
|
|
2954
|
-
alias: "uniqueDesignation",
|
|
2955
|
-
label: "Unique designation"
|
|
2956
|
-
},
|
|
2957
|
-
V: {
|
|
2958
|
-
alias: "type",
|
|
2959
|
-
label: "Equipment/type"
|
|
2960
|
-
},
|
|
2961
|
-
W: {
|
|
2962
|
-
alias: "dtg",
|
|
2963
|
-
label: "Date-time group / O/O"
|
|
2964
|
-
},
|
|
2965
|
-
X: {
|
|
2966
|
-
alias: "altitudeDepth",
|
|
2967
|
-
label: "Altitude/depth"
|
|
2968
|
-
},
|
|
2969
|
-
Y: {
|
|
2970
|
-
alias: "location",
|
|
2971
|
-
label: "Location"
|
|
2972
|
-
},
|
|
2973
|
-
AM: {
|
|
2974
|
-
alias: "distance",
|
|
2975
|
-
label: "Distance/range/radius"
|
|
2976
|
-
},
|
|
2977
|
-
AN: {
|
|
2978
|
-
alias: "azimuth",
|
|
2979
|
-
label: "Azimuth"
|
|
2980
|
-
},
|
|
2981
|
-
AP: {
|
|
2982
|
-
alias: "targetNumber",
|
|
2983
|
-
label: "Target number"
|
|
2984
|
-
},
|
|
2985
|
-
AS: {
|
|
2986
|
-
alias: "country",
|
|
2987
|
-
label: "Country code"
|
|
2988
|
-
}
|
|
2989
|
-
};
|
|
2990
|
-
/** Derived alias→code lookup, so the vocabulary table stays the single source of truth. */
|
|
2991
|
-
const CODE_BY_ALIAS = Object.fromEntries(Object.entries(TEXT_AMPLIFIER_FIELDS).map(([code, { alias }]) => [alias, code]));
|
|
2992
|
-
const CANONICAL_KEYS = new Set(Object.keys(TEXT_AMPLIFIER_FIELDS).flatMap((code) => [
|
|
2993
|
-
code,
|
|
2994
|
-
`${code}1`,
|
|
2995
|
-
`${code}2`
|
|
2996
|
-
]));
|
|
2997
|
-
/**
|
|
2998
|
-
* Resolves a raw placement entry to its object form: a bare `Position` is
|
|
2999
|
-
* legacy shorthand for `{ position }`; an object form passes through only the
|
|
3000
|
-
* fields that are actually valid (`position` must be a finite `[lon, lat]`,
|
|
3001
|
-
* `rotation` a finite number); `undefined` resolves to `{}`.
|
|
3002
|
-
*/
|
|
3003
|
-
function resolveAmplifierPlacement(value) {
|
|
3004
|
-
if (value === void 0) return {};
|
|
3005
|
-
if (Array.isArray(value)) return isValidPosition(value) ? { position: value } : {};
|
|
3006
|
-
const result = {};
|
|
3007
|
-
if (value.position !== void 0 && isValidPosition(value.position)) result.position = value.position;
|
|
3008
|
-
if (typeof value.rotation === "number" && Number.isFinite(value.rotation)) result.rotation = value.rotation;
|
|
3009
|
-
return result;
|
|
3010
|
-
}
|
|
3011
|
-
const EMPTY_TEXT_AMPLIFIERS = Object.freeze({});
|
|
3012
|
-
/** Splits a key like `"country1"` into its base (`"country"`) and suffix (`"1"`). */
|
|
3013
|
-
function splitSuffix(key) {
|
|
3014
|
-
const last = key.charAt(key.length - 1);
|
|
3015
|
-
if (last === "1" || last === "2") return {
|
|
3016
|
-
base: key.slice(0, -1),
|
|
3017
|
-
suffix: last
|
|
3018
|
-
};
|
|
3019
|
-
return {
|
|
3020
|
-
base: key,
|
|
3021
|
-
suffix: ""
|
|
3022
|
-
};
|
|
3023
|
-
}
|
|
3024
|
-
/**
|
|
3025
|
-
* Resolves any accepted key (canonical or friendly alias, with an optional
|
|
3026
|
-
* `1`/`2` suffix) to its canonical key, or `undefined` if unknown — e.g.
|
|
3027
|
-
* `"T"` → `"T"`, `"uniqueDesignation1"` → `"T1"`, `"bogus"` → `undefined`.
|
|
3028
|
-
*/
|
|
3029
|
-
function canonicalTextAmplifierKey(key) {
|
|
3030
|
-
if (CANONICAL_KEYS.has(key)) return key;
|
|
3031
|
-
const { base, suffix } = splitSuffix(key);
|
|
3032
|
-
const code = CODE_BY_ALIAS[base];
|
|
3033
|
-
return code ? `${code}${suffix}` : void 0;
|
|
3034
|
-
}
|
|
3035
|
-
/**
|
|
3036
|
-
* Resolves a `TextAmplifiers` record (canonical keys, friendly aliases, or a
|
|
3037
|
-
* mix) to `CanonicalTextAmplifiers` keyed purely by doctrinal field code.
|
|
3038
|
-
*
|
|
3039
|
-
* - Friendly aliases (with an optional `1`/`2` suffix) map to their canonical
|
|
3040
|
-
* code (e.g. `country1` → `AS1`).
|
|
3041
|
-
* - Values are trimmed; entries that are empty/whitespace-only after
|
|
3042
|
-
* trimming, or not strings, are dropped.
|
|
3043
|
-
* - When both a canonical key and its friendly alias are present for the same
|
|
3044
|
-
* field + suffix, the **canonical key wins** regardless of insertion order.
|
|
3045
|
-
* This holds even for an empty/whitespace canonical value: it suppresses
|
|
3046
|
-
* (clears) the alias entry rather than letting the alias survive.
|
|
3047
|
-
* - Unknown keys are ignored.
|
|
3048
|
-
*
|
|
3049
|
-
* `undefined` or an empty input returns a shared frozen empty object.
|
|
3050
|
-
*/
|
|
3051
|
-
function normalizeTextAmplifiers(input) {
|
|
3052
|
-
if (!input) return EMPTY_TEXT_AMPLIFIERS;
|
|
3053
|
-
const canonicalPresent = /* @__PURE__ */ new Set();
|
|
3054
|
-
for (const [key, rawValue] of Object.entries(input)) if (typeof rawValue === "string" && CANONICAL_KEYS.has(key)) canonicalPresent.add(key);
|
|
3055
|
-
const result = {};
|
|
3056
|
-
for (const [key, rawValue] of Object.entries(input)) {
|
|
3057
|
-
if (typeof rawValue !== "string") continue;
|
|
3058
|
-
const value = rawValue.trim();
|
|
3059
|
-
if (value.length === 0) continue;
|
|
3060
|
-
const canonicalKey = canonicalTextAmplifierKey(key);
|
|
3061
|
-
if (!canonicalKey) continue;
|
|
3062
|
-
if (!CANONICAL_KEYS.has(key) && canonicalPresent.has(canonicalKey)) continue;
|
|
3063
|
-
result[canonicalKey] = value;
|
|
3064
|
-
}
|
|
3065
|
-
return Object.keys(result).length > 0 ? Object.freeze(result) : EMPTY_TEXT_AMPLIFIERS;
|
|
3066
|
-
}
|
|
3067
|
-
//#endregion
|
|
3068
3168
|
//#region src/internal/area-echelon.ts
|
|
3069
3169
|
/**
|
|
3070
3170
|
* Twice the ring's signed area (shoelace). Positive when the ring winds
|
|
@@ -3330,7 +3430,8 @@ function ringCrossingsAtY(verts, target) {
|
|
|
3330
3430
|
crossings.push({
|
|
3331
3431
|
x: a[0] + t * (b[0] - a[0]),
|
|
3332
3432
|
arc: dist + t * length,
|
|
3333
|
-
along: vecNorm(seg)
|
|
3433
|
+
along: vecNorm(seg),
|
|
3434
|
+
edge: [a, b]
|
|
3334
3435
|
});
|
|
3335
3436
|
}
|
|
3336
3437
|
dist += length;
|
|
@@ -3459,36 +3560,6 @@ function ringLabelAnchor(verts) {
|
|
|
3459
3560
|
}
|
|
3460
3561
|
return anchor ?? centroid;
|
|
3461
3562
|
}
|
|
3462
|
-
/** Nearest contact point on a closed ring for a dragged marker anchor. */
|
|
3463
|
-
function nearestPointOnRing(verts, target) {
|
|
3464
|
-
let nearest;
|
|
3465
|
-
let totalArc = 0;
|
|
3466
|
-
for (let i = 0; i < verts.length - 1; i++) {
|
|
3467
|
-
const a = verts[i];
|
|
3468
|
-
const b = verts[i + 1];
|
|
3469
|
-
const seg = vecSub(b, a);
|
|
3470
|
-
const length = vecMag(seg);
|
|
3471
|
-
if (length < 1e-6) continue;
|
|
3472
|
-
const along = vecScale(seg, 1 / length);
|
|
3473
|
-
const t = Math.max(0, Math.min(length, vecDot(vecSub(target, a), along)));
|
|
3474
|
-
const distance = vecMag(vecSub(target, vecAdd(a, vecScale(along, t))));
|
|
3475
|
-
if (!nearest || distance < nearest.distance) nearest = {
|
|
3476
|
-
along,
|
|
3477
|
-
arc: totalArc + t,
|
|
3478
|
-
distance
|
|
3479
|
-
};
|
|
3480
|
-
totalArc += length;
|
|
3481
|
-
}
|
|
3482
|
-
return nearest ? {
|
|
3483
|
-
...nearest,
|
|
3484
|
-
totalArc
|
|
3485
|
-
} : void 0;
|
|
3486
|
-
}
|
|
3487
|
-
function labelHalfExtent(direction, textWidth, textHeight, rotation) {
|
|
3488
|
-
const widthAxis = [Math.cos(rotation), Math.sin(rotation)];
|
|
3489
|
-
const heightAxis = [-widthAxis[1], widthAxis[0]];
|
|
3490
|
-
return .5 * (textWidth * Math.abs(vecDot(direction, widthAxis)) + textHeight * Math.abs(vecDot(direction, heightAxis)));
|
|
3491
|
-
}
|
|
3492
3563
|
/**
|
|
3493
3564
|
* Pushes an area's L-15 text amplifier labels — centered name/H/W-W1 rows and
|
|
3494
3565
|
* west/east "ENY" edge markers — as `part: "label"` Point features (via
|
|
@@ -3570,15 +3641,15 @@ function pushAreaLabels(out, ringVerts, texts, options = {}, amplifierPlacements
|
|
|
3570
3641
|
const labelPoint = placement.position ? project(placement.position[0], placement.position[1]) : [crossing.x, cy];
|
|
3571
3642
|
pushLabel(out, labelPoint, texts.hostile, HORIZONTAL_LABEL_ROTATION, sizeProps, void 0, "N", labelPlacementKey);
|
|
3572
3643
|
const usesDifferentMaskRing = maskRingVerts !== ringVerts;
|
|
3573
|
-
const contact = placement.position || usesDifferentMaskRing ?
|
|
3644
|
+
const contact = placement.position || usesDifferentMaskRing ? nearestPointOnPolyline(maskRingVerts, labelPoint) : {
|
|
3574
3645
|
along: crossing.along,
|
|
3575
3646
|
arc: crossing.arc,
|
|
3576
3647
|
distance: 0,
|
|
3577
|
-
totalArc
|
|
3648
|
+
totalArc,
|
|
3649
|
+
edge: crossing.edge
|
|
3578
3650
|
};
|
|
3579
3651
|
if (!contact) continue;
|
|
3580
|
-
|
|
3581
|
-
if (placement.position && contact.distance > labelHalfExtent(normal, textWidth, textHeight, rotation)) continue;
|
|
3652
|
+
if (placement.position && !labelBoxIntersectsSegment(labelPoint, ...contact.edge, textWidth, textHeight, rotation)) continue;
|
|
3582
3653
|
const tangentExtent = labelHalfExtent(contact.along, textWidth, textHeight, rotation) + clearance;
|
|
3583
3654
|
pushWrappedGap(gaps, contact.arc - tangentExtent, contact.arc + tangentExtent, contact.totalArc);
|
|
3584
3655
|
}
|
|
@@ -12513,4 +12584,4 @@ function assertNever(value) {
|
|
|
12513
12584
|
throw new Error(`Unhandled control measure kind: ${String(value)}`);
|
|
12514
12585
|
}
|
|
12515
12586
|
//#endregion
|
|
12516
|
-
export { DEFAULT_BOUNDARY_OPTIONS as $, DEFAULT_FLOT_OPTIONS as A, centerRadiusDrawRule as At, DEFAULT_GENERIC_TEXT_OPTIONS as B, computeInitialWidthPoint as Bt, DEFAULT_SCREEN_OPTIONS as C, line24DrawRule as Ct, DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS as D, ambushDrawRule as Dt, DEFAULT_FORTIFIED_LINE_OPTIONS as E, line1DrawRule as Et, DEFAULT_GUARD_OPTIONS as F, getMidpointPerpendicularSignedDistance as Ft, DEFAULT_CLASSIC_ARROW_OPTIONS as G, getMetersPerPixel as Gt, DEFAULT_GENERIC_POLYGON_OPTIONS as H, project as Ht, DEFAULT_DELAY_OPTIONS as I, pointOnMidpointPerpendicularAxis as It, DEFAULT_BREACH_OPTIONS as J, DEFAULT_CANALIZE_OPTIONS as K, roundToFixed as Kt, DEFAULT_COVER_OPTIONS as L, snapToMidpointPerpendicular as Lt, DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS as M, blockDrawRule as Mt, DEFAULT_ENCIRCLEMENT_OPTIONS as N, computeDefaultMidpointPerpendicularPoint as Nt, DEFAULT_HANDOVER_LINE_OPTIONS as O, attackByFireDrawRule as Ot, DEFAULT_DISRUPT_OPTIONS as P, createMidpointPerpendicularDrawRule as Pt, DEFAULT_LIGHT_LINE_OPTIONS as Q, DEFAULT_TACTICAL_ARROW_OPTIONS as R, createBaselineFrame as Rt, DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS as S, line26DrawRule as St, DEFAULT_FORTIFIED_AREA_OPTIONS as T, turnDrawRule as Tt, DEFAULT_GENERIC_LINE_OPTIONS as U, unproject as Ut, DEFAULT_GENERIC_RECTANGLE_OPTIONS as V, haversineDistance as Vt, DEFAULT_GENERIC_CIRCLE_OPTIONS as W, EPSILON as Wt, DEFAULT_GENERIC_C2_LINE_OPTIONS as X, DEFAULT_BLOCK_MISSION_TASK_OPTIONS as Y, DEFAULT_ENGINEER_WORK_LINE_OPTIONS as Z, DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS as _, DEFAULT_AMBUSH_OPTIONS as _t, DEFINITIONS as a, DEFAULT_ANTITANK_WALL_OPTIONS as at, DEFAULT_MAIN_ATTACK_OPTIONS as b, axis1DrawRule as bt, getDefaultOptions as c, DEFAULT_AREA_OF_OPERATIONS_OPTIONS as ct, DEFAULT_TURN_OPTIONS as d,
|
|
12587
|
+
export { DEFAULT_BOUNDARY_OPTIONS as $, DEFAULT_FLOT_OPTIONS as A, centerRadiusDrawRule as At, DEFAULT_GENERIC_TEXT_OPTIONS as B, computeInitialWidthPoint as Bt, DEFAULT_SCREEN_OPTIONS as C, line24DrawRule as Ct, DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS as D, ambushDrawRule as Dt, DEFAULT_FORTIFIED_LINE_OPTIONS as E, line1DrawRule as Et, DEFAULT_GUARD_OPTIONS as F, getMidpointPerpendicularSignedDistance as Ft, DEFAULT_CLASSIC_ARROW_OPTIONS as G, getMetersPerPixel as Gt, DEFAULT_GENERIC_POLYGON_OPTIONS as H, project as Ht, DEFAULT_DELAY_OPTIONS as I, pointOnMidpointPerpendicularAxis as It, DEFAULT_BREACH_OPTIONS as J, DEFAULT_CANALIZE_OPTIONS as K, roundToFixed as Kt, DEFAULT_COVER_OPTIONS as L, snapToMidpointPerpendicular as Lt, DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS as M, blockDrawRule as Mt, DEFAULT_ENCIRCLEMENT_OPTIONS as N, computeDefaultMidpointPerpendicularPoint as Nt, DEFAULT_HANDOVER_LINE_OPTIONS as O, attackByFireDrawRule as Ot, DEFAULT_DISRUPT_OPTIONS as P, createMidpointPerpendicularDrawRule as Pt, DEFAULT_LIGHT_LINE_OPTIONS as Q, DEFAULT_TACTICAL_ARROW_OPTIONS as R, createBaselineFrame as Rt, DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS as S, line26DrawRule as St, DEFAULT_FORTIFIED_AREA_OPTIONS as T, turnDrawRule as Tt, DEFAULT_GENERIC_LINE_OPTIONS as U, unproject as Ut, DEFAULT_GENERIC_RECTANGLE_OPTIONS as V, haversineDistance as Vt, DEFAULT_GENERIC_CIRCLE_OPTIONS as W, EPSILON as Wt, DEFAULT_GENERIC_C2_LINE_OPTIONS as X, DEFAULT_BLOCK_MISSION_TASK_OPTIONS as Y, DEFAULT_ENGINEER_WORK_LINE_OPTIONS as Z, DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS as _, DEFAULT_AMBUSH_OPTIONS as _t, DEFINITIONS as a, DEFAULT_ANTITANK_WALL_OPTIONS as at, DEFAULT_MAIN_ATTACK_OPTIONS as b, axis1DrawRule as bt, getDefaultOptions as c, DEFAULT_AREA_OF_OPERATIONS_OPTIONS as ct, DEFAULT_TURN_OPTIONS as d, DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS as dt, DEFAULT_BLOCK_ARROW_OPTIONS as et, DEFAULT_SUPPORTING_ATTACK_OPTIONS as f, DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS as ft, DEFAULT_PICKUP_ZONE_OPTIONS as g, resolveAmplifierPlacement as gt, DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS as h, normalizeTextAmplifiers as ht, CONTROL_MEASURE_METADATA as i, DEFAULT_ATTACK_BY_FIRE_OPTIONS as it, DEFAULT_FIX_OPTIONS as j, disruptDrawRule as jt, DEFAULT_PHASE_LINE_OPTIONS as k, point12DrawRule as kt, listControlMeasureMetadata as l, DEFAULT_AREA_DEFENSE_OPTIONS as lt, DEFAULT_STRONG_POINT_OPTIONS as m, canonicalTextAmplifierKey as mt, resolveStyleHints as n, DEFAULT_BATTLE_POSITION_OPTIONS as nt, getControlMeasureMetadata as o, DEFAULT_ANTITANK_DITCH_OPTIONS as ot, DEFAULT_SUPPORT_BY_FIRE_OPTIONS as p, TEXT_AMPLIFIER_FIELDS as pt, DEFAULT_BYPASS_OPTIONS as q, CONTROL_MEASURE_IDS as r, DEFAULT_ATTACK_HELICOPTER_OPTIONS as rt, getControlMeasureMetadataByValue as s, DEFAULT_ASSEMBLY_AREA_OPTIONS as st, renderControlMeasure as t, DEFAULT_BLOCK_OPTIONS as tt, DEFAULT_TURNING_MOVEMENT_OPTIONS as u, DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS as ut, DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS as v, DEFAULT_AIRBORNE_ATTACK_OPTIONS as vt, DEFAULT_FRONTAL_ATTACK_OPTIONS as w, line23DrawRule as wt, DEFAULT_LANDING_ZONE_OPTIONS as x, supportByFireDrawRule as xt, DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS as y, rectangleDrawRule as yt, DEFAULT_CLEAR_OPTIONS as z, calculateMetrics as zt };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orbat-mapper/control-measures",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.30",
|
|
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",
|