/// <summary>
        /// Returns transmitters which to which this vessel can connect, route efficiency and relays used for each one.
        /// </summary>
        /// <param name="maxHops">Maximum number of relays which can be used for connection to transmitter</param>
        protected IDictionary<VesselMicrowavePersistence, KeyValuePair<double, IEnumerable<VesselRelayPersistence>>> GetConnectedTransmitters(int maxHops = 25) {

            //these two dictionaries store transmitters and relays and best currently known route to them which is replaced if better one is found. 

            var transmitterRouteDictionary = new Dictionary<VesselMicrowavePersistence, MicrowaveRoute>();
            var relayRouteDictionary = new Dictionary<VesselRelayPersistence, MicrowaveRoute>();

            var transmittersToCheck = new List<VesselMicrowavePersistence>();//stores all transmiters to which we want to connect


            foreach (VesselMicrowavePersistence transmitter in vmps) { //first check for direct connection from current vessel to transmitters, will always be optimal
                if (transmitter.getAvailablePower() > 0) { //ignore if no power or transmitter is on the same vessel
                    if (!isInlineReceiver || transmitter.getVessel() != vessel) {
                        if (lineOfSightTo(transmitter.getVessel())) {
                            double distance = ComputeDistance(vessel, transmitter.getVessel());
                            double facingFactor = ComputeFacingFactor(transmitter.getVessel());
                            double efficiency = ComputeTransmissionEfficiency(distance, facingFactor);
                            transmitterRouteDictionary[transmitter] = new MicrowaveRoute(efficiency, distance, facingFactor); //store in dictionary that optimal route to this transmitter is direct connection, can be replaced if better route is found
                        }
                        transmittersToCheck.Add(transmitter);
                    }
                }
            }

            //this algorithm processes relays in groups in which elements of the first group must be visible from receiver, 
            //elements from the second group must be visible by at least one element from previous group and so on...


            var relaysToCheck = new List<VesselRelayPersistence>();//relays which we have to check - all active relays will be here
            var currentRelayGroup = new List<KeyValuePair<VesselRelayPersistence, int>>();//relays which are in line of sight, and we have not yet checked what they can see. Their index in relaysToCheck is also stored

            int relayIndex = 0;
            foreach (VesselRelayPersistence relay in vrps) {
                if (relay.isActive()) {
                    if (lineOfSightTo(relay.getVessel())) {
                        double distance = ComputeDistance(vessel, relay.getVessel());
                        double facingFactor = ComputeFacingFactor(relay.getVessel());
                        double efficiency = ComputeTransmissionEfficiency(distance, facingFactor);
                        relayRouteDictionary[relay] = new MicrowaveRoute(efficiency, distance, facingFactor);//store in dictionary that optimal route to this relay is direct connection, can be replaced if better route is found
                        currentRelayGroup.Add(new KeyValuePair<VesselRelayPersistence, int>(relay, relayIndex));
                    }
                    relaysToCheck.Add(relay);
                    relayIndex++;
                }
            }



            int hops = 0; //number of hops between relays


            //pre-compute distances and visibility thus limiting number of checks to (Nr^2)/2 + NrNt +Nr + Nt
            if (hops < maxHops && transmittersToCheck.Any()) {
                double[,] relayToRelayDistances = new double[relaysToCheck.Count, relaysToCheck.Count];
                double[,] relayToTransmitterDistances = new double[relaysToCheck.Count, transmittersToCheck.Count];

                for (int i = 0; i < relaysToCheck.Count; i++) {
                    var relay = relaysToCheck[i];
                    for (int j = i + 1; j < relaysToCheck.Count; j++) {
                        double visibilityAndDistance = ComputeVisibilityAndDistance(relay, relaysToCheck[j].getVessel());
                        relayToRelayDistances[i, j] = visibilityAndDistance;
                        relayToRelayDistances[j, i] = visibilityAndDistance;
                    }
                    for (int t = 0; t < transmittersToCheck.Count; t++) {
                        relayToTransmitterDistances[i, t] = ComputeVisibilityAndDistance(relay,
                                                                                         transmittersToCheck[t].
                                                                                             getVessel());
                    }
                }

                HashSet<int> coveredRelays = new HashSet<int>();

                //runs as long as there is any relay to which we can connect and maximum number of hops have not been breached
                while (hops < maxHops && currentRelayGroup.Any()) {
                    var nextRelayGroup = new List<KeyValuePair<VesselRelayPersistence, int>>();//will put every relay which is in line of sight of any relay from currentRelayGroup here
                    foreach (var relayEntry in currentRelayGroup) //relays visible from receiver in first iteration, then relays visible from them etc....
                    {
                        var relay = relayEntry.Key;
                        MicrowaveRoute relayRoute = relayRouteDictionary[relay];// current best route for this relay
                        double relayRouteFacingFactor = relayRoute.FacingFactor;// it's always facing factor from the beggining of the route

                        for (int t = 0; t < transmittersToCheck.Count; t++)//check if this relay can connect to transmitters
                        {
                            var transmitter = transmittersToCheck[t];
                            double transmitterDistance = relayToTransmitterDistances[relayEntry.Value, t];
                            if (transmitterDistance > 0)//it's >0 if it can see
                            {
                                double newDistance = relayRoute.Distance + transmitterDistance;// total distance from receiver by this relay to transmitter
                                double efficiencyByThisRelay = ComputeTransmissionEfficiency(newDistance, relayRouteFacingFactor);//efficiency
                                MicrowaveRoute currentOptimalRoute;

                                //this will return true if there is already a route to this transmitter
                                if (transmitterRouteDictionary.TryGetValue(transmitter, out currentOptimalRoute)) {
                                    if (currentOptimalRoute.Efficiency < efficiencyByThisRelay)
                                        //if route using this relay is better then replace the old route
                                        transmitterRouteDictionary[transmitter] = new MicrowaveRoute(efficiencyByThisRelay, newDistance, relayRouteFacingFactor, relay);
                                } else {
                                    //there is no other route to this transmitter yet known so algorithm puts this one as optimal
                                    transmitterRouteDictionary[transmitter] = new MicrowaveRoute(efficiencyByThisRelay,
                                                                                                 newDistance,
                                                                                                 relayRouteFacingFactor,
                                                                                                 relay);
                                }
                            }
                        }

                        for (int r = 0; r < relaysToCheck.Count; r++) {
                            var nextRelay = relaysToCheck[r];
                            if (nextRelay == relay)
                                continue;

                            double distanceToNextRelay = relayToRelayDistances[relayEntry.Value, r];
                            if (distanceToNextRelay > 0) //any relay which is in LOS of this relay
                            {
                                double relayToNextRelayDistance = relayRoute.Distance + distanceToNextRelay;
                                double efficiencyByThisRelay =
                                    ComputeTransmissionEfficiency(relayToNextRelayDistance, relayRouteFacingFactor);

                                MicrowaveRoute currentOptimalPredecessor;

                                if (relayRouteDictionary.TryGetValue(nextRelay, out currentOptimalPredecessor))
                                //this will return true if there is already a route to next relay
                                {
                                    if (currentOptimalPredecessor.Efficiency < efficiencyByThisRelay)
                                        //if route using this relay is better

                                        relayRouteDictionary[nextRelay] = new MicrowaveRoute(efficiencyByThisRelay,
                                                                                             relayToNextRelayDistance,
                                                                                             relayRoute.FacingFactor,
                                                                                             relay);
                                    //we put it in dictionary as optimal

                                } else //there is no other route to this relay yet known so we put this one as optimal
                                {
                                    relayRouteDictionary[nextRelay] = new MicrowaveRoute(efficiencyByThisRelay,
                                                                                         relayToNextRelayDistance,
                                                                                         relayRoute.FacingFactor,
                                                                                         relay);
                                }

                                if (!coveredRelays.Contains(r)) {
                                    nextRelayGroup.Add(new KeyValuePair<VesselRelayPersistence, int>(nextRelay, r));
                                    //in next iteration we will check what next relay can see
                                    coveredRelays.Add(r);
                                }
                            }
                        }
                    }
                    currentRelayGroup = nextRelayGroup;
                    //we don't have to check old relays so we just replace whole List
                    hops++;
                }

            }

            //building final result
            var resultDictionary = new Dictionary<VesselMicrowavePersistence, KeyValuePair<double, IEnumerable<VesselRelayPersistence>>>();

            foreach (var transmitterEntry in transmitterRouteDictionary) {
                Stack<VesselRelayPersistence> relays = new Stack<VesselRelayPersistence>();//Last in, first out so relay visible from receiver will always be first
                VesselRelayPersistence relay = transmitterEntry.Value.PreviousRelay;
                while (relay != null) {
                    relays.Push(relay);
                    relay = relayRouteDictionary[relay].PreviousRelay;
                }
                resultDictionary.Add(transmitterEntry.Key, new KeyValuePair<double, IEnumerable<VesselRelayPersistence>>(transmitterEntry.Value.Efficiency, relays));
            }

            return resultDictionary; //connectedTransmitters;
        }
        /// <summary>
        /// Returns transmitters which to which this vessel can connect, route efficiency and relays used for each one.
        /// </summary>
        /// <param name="maxHops">Maximum number of relays which can be used for connection to transmitter</param>
        protected IDictionary <VesselMicrowavePersistence, KeyValuePair <double, IEnumerable <VesselRelayPersistence> > > GetConnectedTransmitters(int maxHops = 25)
        {
            //these two dictionaries store transmitters and relays and best currently known route to them which is replaced if better one is found.

            var transmitterRouteDictionary = new Dictionary <VesselMicrowavePersistence, MicrowaveRoute>();
            var relayRouteDictionary       = new Dictionary <VesselRelayPersistence, MicrowaveRoute>();

            var transmittersToCheck = new List <VesselMicrowavePersistence>();//stores all transmiters to which we want to connect


            foreach (VesselMicrowavePersistence transmitter in MicrowaveSources.instance.transmitters.Values)
            {     //first check for direct connection from current vessel to transmitters, will always be optimal
                if (transmitter.getAvailablePower() > 0)
                { //ignore if no power or transmitter is on the same vessel
                    if (!isInlineReceiver || transmitter.getVessel() != vessel)
                    {
                        if (lineOfSightTo(transmitter.getVessel()))
                        {
                            double distance     = ComputeDistance(vessel, transmitter.getVessel());
                            double facingFactor = ComputeFacingFactor(transmitter.getVessel());
                            double efficiency   = ComputeTransmissionEfficiency(distance, facingFactor);
                            transmitterRouteDictionary[transmitter] = new MicrowaveRoute(efficiency, distance, facingFactor); //store in dictionary that optimal route to this transmitter is direct connection, can be replaced if better route is found
                        }
                        transmittersToCheck.Add(transmitter);
                    }
                }
            }

            //this algorithm processes relays in groups in which elements of the first group must be visible from receiver,
            //elements from the second group must be visible by at least one element from previous group and so on...


            var relaysToCheck     = new List <VesselRelayPersistence>();                      //relays which we have to check - all active relays will be here
            var currentRelayGroup = new List <KeyValuePair <VesselRelayPersistence, int> >(); //relays which are in line of sight, and we have not yet checked what they can see. Their index in relaysToCheck is also stored

            int relayIndex = 0;

            foreach (VesselRelayPersistence relay in MicrowaveSources.instance.relays.Values)
            {
                if (relay.isActive())
                {
                    if (lineOfSightTo(relay.getVessel()))
                    {
                        double distance     = ComputeDistance(vessel, relay.getVessel());
                        double facingFactor = ComputeFacingFactor(relay.getVessel());
                        double efficiency   = ComputeTransmissionEfficiency(distance, facingFactor);
                        relayRouteDictionary[relay] = new MicrowaveRoute(efficiency, distance, facingFactor);//store in dictionary that optimal route to this relay is direct connection, can be replaced if better route is found
                        currentRelayGroup.Add(new KeyValuePair <VesselRelayPersistence, int>(relay, relayIndex));
                    }
                    relaysToCheck.Add(relay);
                    relayIndex++;
                }
            }



            int hops = 0; //number of hops between relays


            //pre-compute distances and visibility thus limiting number of checks to (Nr^2)/2 + NrNt +Nr + Nt
            if (hops < maxHops && transmittersToCheck.Any())
            {
                double[,] relayToRelayDistances       = new double[relaysToCheck.Count, relaysToCheck.Count];
                double[,] relayToTransmitterDistances = new double[relaysToCheck.Count, transmittersToCheck.Count];

                for (int i = 0; i < relaysToCheck.Count; i++)
                {
                    var relay = relaysToCheck[i];
                    for (int j = i + 1; j < relaysToCheck.Count; j++)
                    {
                        double visibilityAndDistance = ComputeVisibilityAndDistance(relay, relaysToCheck[j].getVessel());
                        relayToRelayDistances[i, j] = visibilityAndDistance;
                        relayToRelayDistances[j, i] = visibilityAndDistance;
                    }
                    for (int t = 0; t < transmittersToCheck.Count; t++)
                    {
                        relayToTransmitterDistances[i, t] = ComputeVisibilityAndDistance(relay,
                                                                                         transmittersToCheck[t].
                                                                                         getVessel());
                    }
                }

                HashSet <int> coveredRelays = new HashSet <int>();

                //runs as long as there is any relay to which we can connect and maximum number of hops have not been breached
                while (hops < maxHops && currentRelayGroup.Any())
                {
                    var nextRelayGroup = new List <KeyValuePair <VesselRelayPersistence, int> >(); //will put every relay which is in line of sight of any relay from currentRelayGroup here
                    foreach (var relayEntry in currentRelayGroup)                                  //relays visible from receiver in first iteration, then relays visible from them etc....
                    {
                        var            relay                  = relayEntry.Key;
                        MicrowaveRoute relayRoute             = relayRouteDictionary[relay]; // current best route for this relay
                        double         relayRouteFacingFactor = relayRoute.FacingFactor;     // it's always facing factor from the beggining of the route

                        for (int t = 0; t < transmittersToCheck.Count; t++)                  //check if this relay can connect to transmitters
                        {
                            var    transmitter         = transmittersToCheck[t];
                            double transmitterDistance = relayToTransmitterDistances[relayEntry.Value, t];
                            if (transmitterDistance > 0)                                                                                   //it's >0 if it can see
                            {
                                double         newDistance           = relayRoute.Distance + transmitterDistance;                          // total distance from receiver by this relay to transmitter
                                double         efficiencyByThisRelay = ComputeTransmissionEfficiency(newDistance, relayRouteFacingFactor); //efficiency
                                MicrowaveRoute currentOptimalRoute;

                                //this will return true if there is already a route to this transmitter
                                if (transmitterRouteDictionary.TryGetValue(transmitter, out currentOptimalRoute))
                                {
                                    if (currentOptimalRoute.Efficiency < efficiencyByThisRelay)
                                    {
                                        //if route using this relay is better then replace the old route
                                        transmitterRouteDictionary[transmitter] = new MicrowaveRoute(efficiencyByThisRelay, newDistance, relayRouteFacingFactor, relay);
                                    }
                                }
                                else
                                {
                                    //there is no other route to this transmitter yet known so algorithm puts this one as optimal
                                    transmitterRouteDictionary[transmitter] = new MicrowaveRoute(efficiencyByThisRelay,
                                                                                                 newDistance,
                                                                                                 relayRouteFacingFactor,
                                                                                                 relay);
                                }
                            }
                        }

                        for (int r = 0; r < relaysToCheck.Count; r++)
                        {
                            var nextRelay = relaysToCheck[r];
                            if (nextRelay == relay)
                            {
                                continue;
                            }

                            double distanceToNextRelay = relayToRelayDistances[relayEntry.Value, r];
                            if (distanceToNextRelay > 0) //any relay which is in LOS of this relay
                            {
                                double relayToNextRelayDistance = relayRoute.Distance + distanceToNextRelay;
                                double efficiencyByThisRelay    =
                                    ComputeTransmissionEfficiency(relayToNextRelayDistance, relayRouteFacingFactor);

                                MicrowaveRoute currentOptimalPredecessor;

                                if (relayRouteDictionary.TryGetValue(nextRelay, out currentOptimalPredecessor))
                                //this will return true if there is already a route to next relay
                                {
                                    if (currentOptimalPredecessor.Efficiency < efficiencyByThisRelay)
                                    {
                                        //if route using this relay is better

                                        relayRouteDictionary[nextRelay] = new MicrowaveRoute(efficiencyByThisRelay,
                                                                                             relayToNextRelayDistance,
                                                                                             relayRoute.FacingFactor,
                                                                                             relay);
                                    }
                                    //we put it in dictionary as optimal
                                }
                                else //there is no other route to this relay yet known so we put this one as optimal
                                {
                                    relayRouteDictionary[nextRelay] = new MicrowaveRoute(efficiencyByThisRelay,
                                                                                         relayToNextRelayDistance,
                                                                                         relayRoute.FacingFactor,
                                                                                         relay);
                                }

                                if (!coveredRelays.Contains(r))
                                {
                                    nextRelayGroup.Add(new KeyValuePair <VesselRelayPersistence, int>(nextRelay, r));
                                    //in next iteration we will check what next relay can see
                                    coveredRelays.Add(r);
                                }
                            }
                        }
                    }
                    currentRelayGroup = nextRelayGroup;
                    //we don't have to check old relays so we just replace whole List
                    hops++;
                }
            }

            //building final result
            var resultDictionary = new Dictionary <VesselMicrowavePersistence, KeyValuePair <double, IEnumerable <VesselRelayPersistence> > >();

            foreach (var transmitterEntry in transmitterRouteDictionary)
            {
                Stack <VesselRelayPersistence> relays = new Stack <VesselRelayPersistence>();//Last in, first out so relay visible from receiver will always be first
                VesselRelayPersistence         relay  = transmitterEntry.Value.PreviousRelay;
                while (relay != null)
                {
                    relays.Push(relay);
                    relay = relayRouteDictionary[relay].PreviousRelay;
                }
                resultDictionary.Add(transmitterEntry.Key, new KeyValuePair <double, IEnumerable <VesselRelayPersistence> >(transmitterEntry.Value.Efficiency, relays));
            }

            return(resultDictionary); //connectedTransmitters;
        }