1. -- 
  2. -- Jan & Uwe R. Zimmer, Australia, July 2011 
  3. -- 
  4.  
  5. with Ada.Containers;                    use Ada.Containers; 
  6. with Ada.Numerics;                      use Ada.Numerics; 
  7. with Ada.Numerics.Elementary_Functions; use Ada.Numerics.Elementary_Functions; 
  8. with Ada.Numerics.Float_Random;         use Ada.Numerics.Float_Random; 
  9. with Ada.Real_Time;                     use Ada.Real_Time; 
  10. with Ada.Task_Identification;            use Ada.Task_Identification; 
  11.  
  12. with Graphics_Configuration;             use Graphics_Configuration; 
  13. with Rotations;                         use Rotations; 
  14. with Swarm_Data;                        use Swarm_Data; 
  15. with Vectors_Conversions;               use Vectors_Conversions; 
  16. with Vectors_3D_LF;                     use Vectors_3D_LF; 
  17. with Vehicle_Message_Type;              use Vehicle_Message_Type; 
  18. with Vehicle_Task_Type;                 use Vehicle_Task_Type; 
  19.  
  20. package body Swarm_Control is 
  21.  
  22.    use Swarm_Vectors; 
  23.  
  24.    -- 
  25.    -- 
  26.    -- 
  27.  
  28.    procedure Append_Random_Swarm (No_Of_Swarm_Elements : Positive  := Initial_No_of_Elements; 
  29.                                   Centre               : Positions := Initial_Swarm_Position; 
  30.                                   Volume_Edge_Length   : Real      := Initual_Edge_Length) is 
  31.  
  32.       Random_Float : Generator; 
  33.  
  34.    begin 
  35.       Swarm_Lock.Lock_Write; 
  36.       Reset (Random_Float); 
  37.       Reserve_Capacity (Swarm_State, Length (Swarm_State) + Count_Type (No_Of_Swarm_Elements)); 
  38.       for i in 1 .. No_Of_Swarm_Elements loop 
  39.          declare 
  40.             New_Element : Swarm_Element_State := 
  41.               (Position     => (Centre (x) + (Random (Random_Float) * Volume_Edge_Length) - Volume_Edge_Length / 2.0, 
  42.                                 Centre (y) + (Random (Random_Float) * Volume_Edge_Length) - Volume_Edge_Length / 2.0, 
  43.                                 Centre (z) + (Random (Random_Float) * Volume_Edge_Length) - Volume_Edge_Length / 2.0), 
  44.                Rotation     => Zero_Rotation, 
  45.                Velocity     => Zero_Vector_3D, 
  46.                Acceleration => Zero_Vector_3D, 
  47.                Charge       => (Level => Full_Charge, Charge_Time => Clock, Charge_No => 0, Globes_Touched => No_Globes_Touched), 
  48.                Neighbours   => new Distance_Vectors.Vector, 
  49.                Controls     => new Vehicle_Controls, 
  50.                Comms        => new Vehicle_Comms, 
  51.                Process      => new Vehicle_Task, 
  52.                Process_Id   => Null_Task_Id, 
  53.                Last_Update  => Clock); 
  54.          begin 
  55.             New_Element.Process.Identify (Swarm_Element_Index (Natural (Length (Swarm_State)) + 1), New_Element.Process_Id); 
  56.             Append (Swarm_State, New_Element); 
  57.          end; 
  58.       end loop; 
  59.       Swarm_Lock.Unlock_Write; 
  60.    end Append_Random_Swarm; 
  61.  
  62.    -- 
  63.    -- 
  64.    -- 
  65.  
  66.    procedure Remove_Vehicle (Element_Ix : Swarm_Element_Index) is 
  67.  
  68.    begin 
  69.       Swarm_Lock.Lock_Write; 
  70.       if Length (Swarm_State) > 1 and then Element_Ix >= First_Index (Swarm_State) and then Element_Ix <= Last_Index (Swarm_State) then 
  71.          declare 
  72.             This_Element : Swarm_Element_State := Element (Swarm_State, Element_Ix); 
  73.          begin 
  74.             abort This_Element.Process.all; 
  75.             loop 
  76.                exit when Is_Terminated (This_Element.Process_Id); 
  77.             end loop; 
  78.             Free_Process    (This_Element.Process); 
  79.             Free_Neighbours (This_Element.Neighbours); 
  80.             Free_Comms      (This_Element.Comms); 
  81.             Free_Controls   (This_Element.Controls); 
  82.             Delete          (Swarm_State, Element_Ix); 
  83.          end; 
  84.       end if; 
  85.       Swarm_Lock.Unlock_Write; 
  86.    end Remove_Vehicle; 
  87.  
  88.    -- 
  89.    -- 
  90.    -- 
  91.  
  92.    procedure Remove_Vehicles (No_Of_Swarm_Elements : Positive  := 1) is 
  93.  
  94.    begin 
  95.       if Natural (Length (Swarm_State)) >= No_Of_Swarm_Elements then 
  96.          for Element_Index in Last_Index (Swarm_State) - No_Of_Swarm_Elements + 1 .. Last_Index (Swarm_State) loop 
  97.             Remove_Vehicle (Element_Index); 
  98.          end loop; 
  99.       end if; 
  100.    end Remove_Vehicles; 
  101.  
  102.    -- 
  103.    -- 
  104.    -- 
  105.  
  106. --     function Sorted_Close_Distances (Element_Index : Swarm_Element_Index; 
  107. --                                      Max_Distance  : Distances) return Distance_Vectors.Vector is 
  108. -- 
  109. --        This_Element  : constant Swarm_Element_State := Element (Swarm_State, Element_Index); 
  110. --        This_Position : constant Positions           := This_Element.Position; 
  111. -- 
  112. --        Close_Dist    : Distance_Vectors.Vector      := Distance_Vectors.Empty_Vector; 
  113. -- 
  114. --     begin 
  115. --        Distance_Vectors.Reserve_Capacity (Close_Dist, Length (Swarm_State) - 1); 
  116. --        for Scan_Index in First_Index (Swarm_State) .. Last_Index (Swarm_State) loop 
  117. --           if Element_Index /= Scan_Index then 
  118. --              declare 
  119. --                 Test_Element   : constant Swarm_Element_State := Element (Swarm_State, Scan_Index); 
  120. --                 Test_Position  : constant Positions           := Test_Element.Position; 
  121. --                 Test_Direction : constant Vector_3D           := This_Position - Test_Position; 
  122. --                 Test_Distance  : constant Distances           := abs (Test_Direction); 
  123. --              begin 
  124. --                 if Test_Distance <= Max_Distance then 
  125. --                    Distance_Vectors.Append (Close_Dist, (Index         => Scan_Index, 
  126. --                                                          Distance      => Test_Distance, 
  127. --                                                          Position_Diff => Test_Direction, 
  128. --                                                          Velocity_Diff => This_Element.Velocity - Test_Element.Velocity)); 
  129. --                 end if; 
  130. --              end; 
  131. --           end if; 
  132. --        end loop; 
  133. --        Sort_Distances.Sort (Close_Dist); 
  134. --        return Close_Dist; 
  135. --     end Sorted_Close_Distances; 
  136. -- 
  137. --     -- 
  138. --     -- 
  139. --     -- 
  140. -- 
  141.    procedure Sorted_Close_Distances (Close_Dist    : in out Distance_Vectors.Vector; 
  142.                                      Element_Index : Swarm_Element_Index; 
  143.                                      Max_Distance  : Distances) is 
  144.  
  145.       This_Element  : constant Swarm_Element_State := Element (Swarm_State, Element_Index); 
  146.       This_Position : constant Positions           := This_Element.Position; 
  147.  
  148.    begin 
  149.       Distance_Vectors.Clear (Close_Dist); 
  150.       Distance_Vectors.Reserve_Capacity (Close_Dist, Length (Swarm_State) - 1); 
  151.       for Scan_Index in First_Index (Swarm_State) .. Last_Index (Swarm_State) loop 
  152.          if Element_Index /= Scan_Index then 
  153.             declare 
  154.                Test_Element   : constant Swarm_Element_State := Element (Swarm_State, Scan_Index); 
  155.                Test_Position  : constant Positions           := Test_Element.Position; 
  156.                Test_Direction : constant Vector_3D           := This_Position - Test_Position; 
  157.                Test_Distance  : constant Distances           := abs (Test_Direction); 
  158.             begin 
  159.                if Test_Distance <= Max_Distance then 
  160.                   Distance_Vectors.Append (Close_Dist, (Index         => Scan_Index, 
  161.                                                         Distance      => Test_Distance, 
  162.                                                         Position_Diff => Test_Direction, 
  163.                                                         Velocity_Diff => This_Element.Velocity - Test_Element.Velocity)); 
  164.                end if; 
  165.             end; 
  166.          end if; 
  167.       end loop; 
  168.       Sort_Distances.Sort (Close_Dist); 
  169.    end Sorted_Close_Distances; 
  170.  
  171.    -- 
  172.    -- 
  173.    -- 
  174.  
  175.    procedure Set_Acceleration (Element_Index : Swarm_Element_Index) is 
  176.  
  177.       This_Element  : Swarm_Element_State := Element (Swarm_State, Element_Index); 
  178.       Acceleration  : Accelerations       := Zero_Vector_3D; 
  179.  
  180.    begin 
  181.       Sorted_Close_Distances (This_Element.Neighbours.all, Element_Index, Detection_Range); 
  182.       for Distance_Index in Distance_Vectors.First_Index (This_Element.Neighbours.all) .. Distance_Vectors.Last_Index (This_Element.Neighbours.all) loop 
  183.          declare 
  184.             Distance_Entry : constant Distance_Entries := Distance_Vectors.Element (This_Element.Neighbours.all, Distance_Index); 
  185.          begin 
  186.  
  187.             -- Uncontrolled vehicles 
  188.             if This_Element.Controls.Read_Throttle = 0.0 then 
  189.  
  190.                -- Attraction and repulsion forces between vehicles 
  191.                Acceleration := Acceleration + Inter_Swarm_Acceleration (Distance_Entry.Distance) * Norm (Distance_Entry.Position_Diff); 
  192.  
  193.                -- Alignment forces 
  194.                if Distance_Entry.Distance <= Velocity_Matching_Range then 
  195.                   Acceleration := Acceleration + Velocity_Matching (This_Element.Velocity, Distance_Entry.Velocity_Diff); 
  196.                end if; 
  197.  
  198.             -- Controlled vehicles 
  199.             elsif Distance_Entry.Distance <= Unconditional_Repulse_Dist then 
  200.  
  201.                -- Unconditional repulsion for controlled vehicles 
  202.                Acceleration := Acceleration + Inter_Swarm_Repulsion (Distance_Entry.Distance) * Norm (Distance_Entry.Position_Diff); 
  203.  
  204.             end if; 
  205.  
  206.          end; 
  207.       end loop; 
  208.  
  209.       -- Controlled vehicles 
  210.       if This_Element.Controls.Read_Throttle /= 0.0 then 
  211.  
  212.          -- Approach the set target 
  213.          declare 
  214.             Target_Vector                     : constant Vector_3D := This_Element.Controls.Read_Steering - This_Element.Position; 
  215.             Norm_Target_Vector                : constant Vector_3D := Norm (Target_Vector); 
  216.             Abs_Target_Vector                 : constant Real := abs (Target_Vector); 
  217.             Abs_Velocity                      : constant Real := abs (This_Element.Velocity); 
  218.             Angle_Between_Target_and_Velocity : constant Real := Angle_Between (Target_Vector, This_Element.Velocity); 
  219.          begin 
  220.             if Abs_Target_Vector < Target_Fetch_Range then 
  221.                -- Target reached, switch to idle throttle 
  222.                This_Element.Controls.Set_Throttle (Idle_Throttle); 
  223.             else 
  224.                -- Accelerate to constant speed towards target, dampen lateral velocities 
  225.                Acceleration := Acceleration 
  226.                  + (This_Element.Controls.Read_Throttle 
  227.                     * Approach_Acceleration (Abs_Velocity * Cos (Angle_Between_Target_and_Velocity)) 
  228.                     * Norm_Target_Vector) 
  229.                  - Norm (This_Element.Velocity) * (Intented_Framerate / 5.0) * Abs_Velocity * Sin (Angle_Between_Target_and_Velocity); 
  230.             end if; 
  231.          end; 
  232.       end if; 
  233.  
  234.       -- Friction 
  235.       This_Element.Acceleration := Acceleration - Norm (This_Element.Velocity) * (abs (This_Element.Velocity) * Friction)**2; 
  236.  
  237.       Replace_Element (Swarm_State, Element_Index, This_Element); 
  238.    end Set_Acceleration; 
  239.  
  240.    -- 
  241.    -- 
  242.    -- 
  243.  
  244.    procedure Set_All_Accelerations is 
  245.  
  246.    begin 
  247.       for Element_Index in First_Index (Swarm_State) .. Last_Index (Swarm_State) loop 
  248.          Set_Acceleration (Element_Index); 
  249.       end loop; 
  250.    end Set_All_Accelerations; 
  251.  
  252.    -- 
  253.    -- 
  254.    -- 
  255.  
  256.    procedure Forward_Messages (Element_Index : Swarm_Element_Index) is 
  257.  
  258.       This_Element              : constant Swarm_Element_State := Element (Swarm_State, Element_Index); 
  259.       Message_To_Be_Distributed : Inter_Vehicle_Messages; 
  260.  
  261.    begin 
  262.       while This_Element.Comms.Has_Outgoing_Messages loop 
  263.          This_Element.Comms.Fetch_Message (Message_To_Be_Distributed); 
  264.          Check_Neighbours : for Distance_Index in Distance_Vectors.First_Index (This_Element.Neighbours.all) .. Distance_Vectors.Last_Index (This_Element.Neighbours.all) loop 
  265.             declare 
  266.                Distance_Entry : constant Distance_Entries := Distance_Vectors.Element (This_Element.Neighbours.all, Distance_Index); 
  267.             begin 
  268.                if Distance_Entry.Distance <= Comms_Range then 
  269.                   Element (Swarm_State, Distance_Entry.Index).Comms.Push_Message (Message_To_Be_Distributed); 
  270.                else 
  271.                   exit Check_Neighbours; 
  272.                end if; 
  273.             end; 
  274.          end loop Check_Neighbours; 
  275.       end loop; 
  276.    end Forward_Messages; 
  277.  
  278.    -- 
  279.    -- 
  280.    -- 
  281.  
  282.    procedure Forward_All_Messages is 
  283.  
  284.    begin 
  285.       for Element_Index in First_Index (Swarm_State) .. Last_Index (Swarm_State) loop 
  286.          Forward_Messages (Element_Index); 
  287.       end loop; 
  288.    end Forward_All_Messages; 
  289.  
  290.    -- 
  291.    -- 
  292.    -- 
  293.  
  294.    procedure Move_Element (Element_Index : Swarm_Element_Index) is 
  295.  
  296.       This_Element : Swarm_Element_State := Element (Swarm_State, Element_Index); 
  297.       Interval     : constant Float      := Float'Min (Float (To_Duration (Clock - This_Element.Last_Update)), 
  298.                                                        Max_Update_Interval); 
  299.  
  300.    begin 
  301.       This_Element.Velocity    := This_Element.Velocity + (Interval * This_Element.Acceleration); 
  302.       This_Element.Position    := This_Element.Position + (Interval * This_Element.Velocity); 
  303.  
  304.       This_Element.Charge.Level := Vehicle_Charges 
  305.         (Float'Max (Float (Empty_Charge), 
  306.                     Float'Min (Float (Full_Charge), 
  307.            Float (This_Element.Charge.Level) - (Interval * Charging_Setup.Discharge_Rate_Per_Sec)))); 
  308.  
  309.       for Globe_Ix in Globes'Range loop 
  310.          if not This_Element.Charge.Globes_Touched (Globe_Ix) 
  311.            and then abs (This_Element.Position - Globes (Globe_Ix).Position) <= Energy_Globe_Detection then 
  312.  
  313.             if Clock - This_Element.Charge.Charge_Time > Charging_Setup.Max_Globe_Interval then 
  314.                This_Element.Charge.Globes_Touched := No_Globes_Touched; 
  315.                This_Element.Charge.Charge_No      := 0; 
  316.             end if; 
  317.  
  318.             This_Element.Charge.Charge_No                 := This_Element.Charge.Charge_No + 1; 
  319.             This_Element.Charge.Globes_Touched (Globe_Ix) := True; 
  320.             This_Element.Charge.Charge_Time               := Clock; 
  321.  
  322.             if This_Element.Charge.Charge_No = Charging_Setup.Globes_Required then 
  323.                This_Element.Charge.Level          := Full_Charge; 
  324.                This_Element.Charge.Charge_No      := 0; 
  325.                This_Element.Charge.Globes_Touched := No_Globes_Touched; 
  326.             end if; 
  327.  
  328.          end if; 
  329.       end loop; 
  330.  
  331.       This_Element.Last_Update := Clock; 
  332.       Replace_Element (Swarm_State, Element_Index, This_Element); 
  333.    end Move_Element; 
  334.  
  335.    -- 
  336.    -- 
  337.    -- 
  338.  
  339.    procedure Move_All_Elements is 
  340.  
  341.    begin 
  342.       for Element_Index in First_Index (Swarm_State) .. Last_Index (Swarm_State) loop 
  343.          Move_Element (Element_Index); 
  344.       end loop; 
  345.    end Move_All_Elements; 
  346.  
  347.    -- 
  348.    -- 
  349.    -- 
  350.  
  351.    procedure Update_Rotation (Element_Index : Swarm_Element_Index) is 
  352.  
  353.       function Vector_Yaw (In_Vector : Vector_3D) return Float is 
  354.  
  355.       begin 
  356.          if In_Vector (x) = 0.0 and then In_Vector (z) = 0.0 then 
  357.             return 0.0; 
  358.          else 
  359.             return Arctan (In_Vector (x), In_Vector (z)); 
  360.          end if; 
  361.       end Vector_Yaw; 
  362.  
  363.       function Vector_Pitch (In_Vector : Vector_3D) return Float is 
  364.  
  365.       begin 
  366.          return (Pi / 2.0) - Angle_Between (In_Vector, (0.0, 1.0, 0.0)); 
  367.       end Vector_Pitch; 
  368.  
  369.       This_Element : Swarm_Element_State := Element (Swarm_State, Element_Index); 
  370.  
  371.       Velocity      : constant Vector_3D := This_Element.Velocity; 
  372.       Element_Yaw   : constant Real      := Vector_Yaw   (Velocity); 
  373.       Element_Pitch : constant Real      := Vector_Pitch (Velocity); 
  374.  
  375.       Rotation      : constant Quaternion_Rotation := To_Rotation (0.0, -Element_Pitch, Element_Yaw + Pi); 
  376.       Norm_Acc      : constant Vector_3D := Rotate (This_Element.Acceleration, Rotation); 
  377.       Lateral_Acc   : constant Real      := Norm_Acc (x) * abs (Velocity); 
  378.       Element_Roll  : constant Real := 
  379.         Real'Max (-Pi / 2.0, 
  380.                   Real'Min (Pi / 2.0, 
  381.                             Lateral_Acc * (Pi / 2.0) / Max_Assumed_Acceleration)); 
  382.  
  383.    begin 
  384.       This_Element.Rotation := To_Rotation (Element_Roll, -Element_Pitch, -Element_Yaw + Pi); 
  385.       Replace_Element (Swarm_State, Element_Index, This_Element); 
  386.    end Update_Rotation; 
  387.  
  388.    --- 
  389.    --- 
  390.    --- 
  391.  
  392.    procedure Update_All_Rotations is 
  393.  
  394.    begin 
  395.       for Element_Index in First_Index (Swarm_State) .. Last_Index (Swarm_State) loop 
  396.          Update_Rotation (Element_Index); 
  397.       end loop; 
  398.    end Update_All_Rotations; 
  399.  
  400.    -- 
  401.    -- 
  402.    -- 
  403.  
  404.    procedure Remove_Empties is 
  405.  
  406.    begin 
  407.       if Length (Swarm_State) > 1 then 
  408.          declare 
  409.             Element_Index : Swarm_Element_Index := First_Index (Swarm_State); 
  410.          begin 
  411.             while Element_Index <= Last_Index (Swarm_State) and then Length (Swarm_State) > 1 loop 
  412.                if Element (Swarm_State, Element_Index).Charge.Level = Empty_Charge then 
  413.                   Remove_Vehicle (Element_Index); 
  414.                else 
  415.                   Element_Index := Element_Index + 1; 
  416.                end if; 
  417.             end loop; 
  418.          end; 
  419.       end if; 
  420.    end Remove_Empties; 
  421.  
  422.    -- 
  423.    -- 
  424.    -- 
  425.  
  426.    function Centre_Of_Gravity return Vector_3D is 
  427.  
  428.       Acc_Positions : Vector_3D_LF := Zero_Vector_3D_LF; 
  429.  
  430.    begin 
  431.       Swarm_Lock.Lock_Read; 
  432.       for Element_Index in First_Index (Swarm_State) .. Last_Index (Swarm_State) loop 
  433.          Acc_Positions := Acc_Positions + To_Vector_3D_LF (Element (Swarm_State, Element_Index).Position); 
  434.       end loop; 
  435.       Swarm_Lock.Unlock_Read; 
  436.       return To_Vector_3D ((1.0 / Long_Float (Length (Swarm_State))) * Acc_Positions); 
  437.    end Centre_Of_Gravity; 
  438.  
  439.    -- 
  440.    -- 
  441.    -- 
  442.  
  443.    function Mean_Velocity return Vector_3D is 
  444.  
  445.       Acc_Velocity : Vector_3D_LF := Zero_Vector_3D_LF; 
  446.  
  447.    begin 
  448.       Swarm_Lock.Lock_Read; 
  449.       for Element_Index in First_Index (Swarm_State) .. Last_Index (Swarm_State) loop 
  450.          Acc_Velocity := Acc_Velocity + To_Vector_3D_LF (Element (Swarm_State, Element_Index).Velocity); 
  451.       end loop; 
  452.       Swarm_Lock.Unlock_Read; 
  453.       return To_Vector_3D ((1.0 / Long_Float (Length (Swarm_State))) * Acc_Velocity); 
  454.    end Mean_Velocity; 
  455.  
  456.    -- 
  457.    -- 
  458.    -- 
  459.  
  460.    function Mean_Velocity return Real is 
  461.  
  462.       Acc_Velocity : Long_Float := 0.0; 
  463.  
  464.    begin 
  465.       Swarm_Lock.Lock_Read; 
  466.       for Element_Index in First_Index (Swarm_State) .. Last_Index (Swarm_State) loop 
  467.          Acc_Velocity := Acc_Velocity + abs (To_Vector_3D_LF (Element (Swarm_State, Element_Index).Velocity)); 
  468.       end loop; 
  469.       Swarm_Lock.Unlock_Read; 
  470.       return Real (Acc_Velocity / Long_Float (Length (Swarm_State))); 
  471.    end Mean_Velocity; 
  472.  
  473.    -- 
  474.    -- 
  475.    -- 
  476.  
  477.    function Maximal_Radius        return Real is 
  478.  
  479.       CoG    : constant Vector_3D := Centre_Of_Gravity; 
  480.  
  481.       Radius : Real := 0.0; 
  482.  
  483.    begin 
  484.       Swarm_Lock.Lock_Read; 
  485.       for Element_Index in First_Index (Swarm_State) .. Last_Index (Swarm_State) loop 
  486.          declare 
  487.             Distance_from_CoG : constant Real := abs (CoG - Element (Swarm_State, Element_Index).Position); 
  488.          begin 
  489.             Radius := Real'Max (Radius, Distance_from_CoG); 
  490.          end; 
  491.       end loop; 
  492.       Swarm_Lock.Unlock_Read; 
  493.       return Radius; 
  494.    end Maximal_Radius; 
  495.  
  496.    -- 
  497.    -- 
  498.    -- 
  499.  
  500.    function Mean_Radius        return Real is 
  501.  
  502.       CoG : constant Vector_3D := Centre_Of_Gravity; 
  503.  
  504.       Acc_Radius : Long_Float := 0.0; 
  505.  
  506.    begin 
  507.       Swarm_Lock.Lock_Read; 
  508.       for Element_Index in First_Index (Swarm_State) .. Last_Index (Swarm_State) loop 
  509.          declare 
  510.             Distance_from_CoG : constant Real := abs (CoG - Element (Swarm_State, Element_Index).Position); 
  511.          begin 
  512.             Acc_Radius := Acc_Radius + Long_Float (Distance_from_CoG); 
  513.          end; 
  514.       end loop; 
  515.       Swarm_Lock.Unlock_Read; 
  516.       return Real (Acc_Radius / Long_Float (Length (Swarm_State))); 
  517.    end Mean_Radius; 
  518.  
  519.    -- 
  520.    -- 
  521.    -- 
  522.  
  523.    function Mean_Closest_Distance return Real is 
  524.  
  525.       Acc_Distance : Long_Float := 0.0; 
  526.  
  527.    begin 
  528.       Swarm_Lock.Lock_Read; 
  529.       for Element_Index in First_Index (Swarm_State) .. Last_Index (Swarm_State) loop 
  530.          declare 
  531.             This_Element     : constant Swarm_Element_State     := Element (Swarm_State, Element_Index); 
  532.             Neighbours       : constant Distance_Vectors.Vector := This_Element.Neighbours.all; 
  533.          begin 
  534.             if Distance_Vectors.Length (Neighbours) > 0 then 
  535.                declare 
  536.                   Closest_Distance : constant Real                    := 
  537.                     Distance_Vectors.Element (Neighbours, Distance_Vectors.First_Index (Neighbours)).Distance; 
  538.                begin 
  539.                   Acc_Distance := Acc_Distance + Long_Float (Closest_Distance); 
  540.                end; 
  541.             end if; 
  542.          end; 
  543.       end loop; 
  544.       Swarm_Lock.Unlock_Read; 
  545.       return Real (Acc_Distance / Long_Float (Length (Swarm_State))); 
  546.    end Mean_Closest_Distance; 
  547.  
  548.    -- 
  549.  
  550. end Swarm_Control;